2013-05-18
■ JOI春合宿 埋めた分 No.1
Mall Lv.5
二次元累積和をとる
#include#include #define INF 1000000000LL long long rui[1005][1005]={}; int m,n; long long field[1005][1005]; int a,b; long long ret=1e18; int main() { scanf("%d %d",&m,&n); scanf("%d %d",&a,&b); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { scanf("%lld",&field[i][j]); if(field[i][j]==-1) field[i][j]=INF; } } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { rui[i][j]=rui[i-1][j]+rui[i][j-1]-rui[i-1][j-1]+field[i][j]; } } for(int i=1;i<=n-b+1;i++) { for(int j=1;j<=m-a+1;j++) { ret=std::min(ret,rui[i+b-1][j+a-1]-rui[i+b-1][j-1]-rui[i-1][j+a-1]+rui[i-1][j-1]); } } printf("%lld%c",ret,10); }
Building Lv.5
狭義最長増加部分列
include#include int main() { int n; int height[1005]; int dp[1005]={}; int ret=0; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&height[i]); } for(int i=1;i<=n;i++) { dp[i]=1; for(int j=1;jif(height[i]>height[j]) dp[i]=std::max(dp[i],dp[j]+1); } ret=std::max(ret,dp[i]); } printf("%d%c",ret,10); }
Fermat Lv.8
x^n+y^n≡z^n (mod p)
のとき、
a≡x^n, b≡y^n,c≡z^n (mod p)とすると
c=0の時を除くとき
1<=c<=p-1より pが素数であることから gcd(c,p)=1であるので
cd≡1(mod p)なる逆元dが存在し、
a+b≡c (mod p) より ad+bd≡cd (mod p)であるので、ad+bd≡1 (mod p).
つまり1<=z<=p-1の時、z^nがとりうる値それぞれについてmod p における逆元が存在し、
それを式全体にかけることによってc=1の場合に対応させることができるので
答えは(c=0である(x,y,z)の総数)+(c=1である(x,y,z)の総数)*(cのとりうる値の総数(1<=z<=p-1))で求められる。
#include#include #include #include #include #include #include #include #include #include #include #include #include using namespace std; typedef pair<int,int> P; typedef pair<int,P> P1; typedef pair P2; #define pu push #define pb push_back #define mp make_pair #define eps 1e-7 #define INF 2000000000 int mod[10005][15]={}; int cou[10005]; set<int>s; int main(){ int p,n; scanf("%d %d",&p,&n); for(int j=0;j
0]=j%p; for(int i=1;i<=20;i++){ mod[j][i]=(mod[j][i-1]*mod[j][i-1])%p; } int se=1; for(int i=0;i<=20;i++){ if(((n>>i)&1)){ se*=mod[j][i]; se%=p; } } cou[se]++; s.insert(se); } int ans1=cou[0]*cou[0]*cou[0]; int ans2=0; for(int i=0;i
0]*cou[i]*cou[p-i]; } ans2+=cou[1]*cou[1]*cou[0]*2; for(int i=0;i
1]*cou[i]*cou[p+1-i]; } printf("%d\n",ans1+ans2*(int)s.size()-ans2); return 0; }
Anagram Lv.7
重複に気をつけてcombinationの積をとって足して+1する
#include#include #include #include #include #include #include #include #include #include #include #include #include using namespace std; typedef pair<int,int> P; typedef pair<int,P> P1; typedef pair P2; #define pu push #define pb push_back #define mp make_pair #define eps 1e-7 #define INF 2000000000 long long mem[25][25]={}; string str; map<char,int>ma; long long conb(int n,int m) { if(mem[n][m]) return mem[n][m]; if(m==0 || n==m) return 1; if(n
0) return 0; return mem[n][m]=conb(n-1,m)+conb(n-1,m-1); } int main(){ cin >> str; for(int i=0;i long long ret=0; for(int i=0;i char>candidate; for(int j=i+1;j if(str[i]>str[j]) { candidate.pb(str[j]); } } sort(candidate.begin(),candidate.end()); candidate.erase(unique(candidate.begin(),candidate.end()),candidate.end()); for(int j=0;j int am=str.size()-i-1; map<char,int>::iterator it; long long res=1; for(it=ma.begin();it!=ma.end();++it) { res*=conb(am,it->second); am-=it->second; } ma[candidate[j]]++; ret+=res; } ma[str[i]]--; } printf("%lld\n",ret+1LL); }
Route Lv.8
二個前の頂点, 一個前の頂点 を状態にもってdijkstraすればいい。
bug partyしたのでまた今度書きます。
Fiber Lv.5
UFするなりBFSするなりどうとでも。
#include#include #include #include using namespace std; vector<int>edge[10005]; bool used[10005]={}; int main() { int n,m; scanf("%d %d",&n,&m); for(int i=0;i int a,b; scanf("%d %d",&a,&b); edge[a].push_back(b); edge[b].push_back(a); } int cnt=0; for(int i=1;i<=n;i++) { if(used[i]) continue; used[i]=true; queue<int>que; que.push(i); while(!que.empty()) { int ii=que.front(); que.pop(); for(int j=0;j if(!used[edge[ii][j]]) { used[edge[ii][j]]=true; que.push(edge[ii][j]); } } } cnt++; } printf("%d%c",cnt-1,10); return 0; }
Committee Lv.7
木上の再帰か... と思ったけど
dp[i] = i番目の人を含み、その人以下の人とのやる気の合計の最大値
とすると簡単。
#include#include #include using namespace std; int dp[100005]={}; int up[100005]; vector<int> down[100005]; int power[100005]; int n; int main() { scanf("%d",&n); int flag=-10000; for(int i=1;i<=n;i++) { int a,b; scanf("%d %d",&a,&b); up[i]=a; down[a].push_back(i); power[i]=b; flag=std::max(flag,b); } if(flag<=0) { printf("%d%c",flag,10); return 0; } int ret=0; for(int i=n;i>=1;i--) { int sum=0; for(int j=0;j if(dp[down[i][j]]>0) sum+=dp[down[i][j]]; dp[i]=power[i]+sum; ret=max(ret,dp[i]); } printf("%d%c",ret,10); }
Sheet Lv.8
AのマスがBの存在する領域にある時B->Aの辺を結んでトポロジカルソートすればいい
けどまだ書いてないです
Flu Lv.9
点を列挙してBFSする。
なんでLv.9なんだろう
#include#include #include #include #include #include using namespace std; vector<int>go[100005]; bool used[100005]={}; int ex[1005][1005]={}; vector<int>za[1005]; int x[100005],y[100005]; int n,m,d,K; int main() { scanf("%d %d %d %d",&n,&m,&d,&K); for(int i=1;i<=n;i++) { int a,b; scanf("%d %d",&a,&b); x[i]=a; y[i]=b; ex[a][b]=i; za[a].push_back(b); } for(int i=0;i<1005;i++) { if(za[i].size()) sort(za[i].begin(),za[i].end()); } for(int i=1;i<=n;i++) { for(int j=max(0,x[i]-25);j<=min(1000,x[i]+25);j++) { int p=lower_bound(za[j].begin(),za[j].end(),y[i])-za[j].begin(); for(int k=p;k if(abs(x[i]-j)*abs(x[i]-j)+abs(za[j][k]-y[i])*abs(za[j][k]-y[i])<=d*d) { go[i].push_back(ex[j][za[j][k]]); } else break; } for(int k=p-1;k>=0;k--) { if(abs(x[i]-j)*abs(x[i]-j)+abs(za[j][k]-y[i])*abs(za[j][k]-y[i])<=d*d) { go[i].push_back(ex[j][za[j][k]]); } else break; } } } queue<int>que; que.push(1); int ret=0; used[1]=true; for(int i=1;i<=K;i++) { int e=(int)que.size(); if(K-m+1<=i-1) ret+=e; for(int j=0;j int fr=que.front(); que.pop(); for(int k=0;k if(!used[go[fr][k]]) { used[go[fr][k]]=true; que.push(go[fr][k]); } } } } printf("%d%c",ret+(int)que.size(),10); }
Nile.com Lv.6
DP.
ちょっとした工夫がいる。明らかにLv.6より難しいとおもった
#include#include using namespace std; long long dp[3005][4][366]; int n,d; int main() { scanf("%d %d",&n,&d); long long zan=1e10; for(int i=0;i<3005;i++)for(int j=0;j<4;j++)for(int k=0;k<366;k++)dp[i][j][k]=1e10; for(int i=1;i<=n;i++) { long long int p; scanf("%lld",&p); dp[i][1][1]=p; zan=min(zan,p); } for(int i=2;i<=d;i++) { long long prev=1e10; for(int j=1;j<=n;j++) { long long int p; scanf("%lld",&p); dp[j][1][i]=zan+p; dp[j][2][i]=dp[j][1][i-1]+p/10*9; dp[j][3][i]=min(dp[j][2][i-1],dp[j][3][i-1])+p/10*7; for(int k=1;k<=3;k++) dp[j][k][i]=min(dp[j][k][i],10000000000ll); prev=min(min(prev,dp[j][1][i]),min(dp[j][2][i],dp[j][3][i])); } zan=prev; } printf("%lld%c",zan,10); }
いじょーです〜