Codeforces Round #286 (Div. 1)
久しぶりにコンテスト参加。問題は各地でたくさん解いているんだけど。
D:
平方分割的あれやるだけ。何も考えないし何でDなんだ。
#include<stdio.h> #include<algorithm> #include<vector> #include<map> using namespace std; int p[110000]; int q[110000]; int r[110000]; int UF[402][101000]; int FIND(int a,int b){ if(UF[a][b]<0)return b; return UF[a][b]=FIND(a,UF[a][b]); } void UNION(int a,int b,int c){ b=FIND(a,b); c=FIND(a,c); if(b==c)return ; UF[a][b]+=UF[a][c]; UF[a][c]=b; } int sz[110000]; int conv[110000]; vector<int>sho[110000]; int tuf[520]; pair<int,int> sm[8000000]; int S; int Find(int a){ if(tuf[a]<0)return a; return tuf[a]=Find(tuf[a]); } void Union(int a,int b){ a=Find(a);b=Find(b);if(a==b)return ; tuf[a]+=tuf[b];tuf[b]=a; } int cj[600]; int main(){ int a,b; scanf("%d%d",&a,&b); for(int i=0;i<b;i++){ scanf("%d%d%d",p+i,q+i,r+i); p[i]--;q[i]--;r[i]--; sz[r[i]]++; } for(int i=0;i<402;i++)for(int j=0;j<101000;j++)UF[i][j]=-1; int ind=0; for(int i=0;i<b;i++)conv[i]=-1; for(int i=0;i<b;i++){ if(sz[i]>=250){ conv[i]=ind++; } } for(int i=0;i<b;i++){ if(~conv[r[i]])UNION(conv[r[i]],p[i],q[i]); else sho[r[i]].push_back(i); } for(int i=0;i<b;i++){ if(!sho[i].size())continue; // printf("%d %d\n",i,(int)sho[i].size()); for(int j=0;j<510;j++)tuf[j]=-1; map<int,int> M; int at=0; for(int j=0;j<sho[i].size();j++){ // printf("%d\n",sho[i][j]); int L,R; if(!M.count(p[sho[i][j]])){ L=at; cj[at]=p[sho[i][j]]; M[p[sho[i][j]]]=at; at++; }else L=M[p[sho[i][j]]]; if(!M.count(q[sho[i][j]])){ R=at; cj[at]=q[sho[i][j]]; M[q[sho[i][j]]]=at; at++; }else R=M[q[sho[i][j]]]; //printf("%d %d\n",L,R); Union(L,R); } //printf("%d\n",i); for(int j=0;j<at;j++)for(int k=j+1;k<at;k++){ if(Find(j)==Find(k))sm[S++]=(make_pair(min(cj[j],cj[k]),max(cj[j],cj[k]))); } //printf("%d\n",i); } std::sort(sm,sm+S); int c; scanf("%d",&c); for(int i=0;i<c;i++){ int s,t; scanf("%d%d",&s,&t);s--;t--; int ret=0; for(int j=0;j<ind;j++)if(FIND(j,s)==FIND(j,t))ret++; ret+=upper_bound(sm,sm+S,make_pair(min(s,t),max(s,t)))-lower_bound(sm,sm+S,make_pair(min(s,t),max(s,t))); printf("%d\n",ret); } }
A:
DP(二つキーを持つが、片方の幅が狭い)
なんでこんなのがAなんだ。というかこういうのはCF独特感すらある。
#include<stdio.h> #include<algorithm> using namespace std; int dp[31000][610]; int val[31000]; int main(){ int a,b; scanf("%d%d",&a,&b); int T=b; for(int i=0;i<a;i++){ int p;scanf("%d",&p); val[p]++; } for(int i=0;i<31000;i++)for(int j=0;j<610;j++)dp[i][j]=-999999999; dp[b][300]=val[b]; for(int i=b;i<30000;i++){ for(int j=0;j<610;j++){ if(dp[i][j]<0)continue; int sp=T+j-300; if(j&&sp>1&&i+sp-1<=30000)dp[i+sp-1][j-1]=max(dp[i+sp-1][j-1],dp[i][j]+val[i+sp-1]); if(i+sp<=30000)dp[i+sp][j]=max(dp[i+sp][j],dp[i][j]+val[i+sp]); if(j<609&&i+sp+1<=30000)dp[i+sp+1][j+1]=max(dp[i+sp+1][j+1],dp[i][j]+val[i+sp+1]); } } int ret=0; for(int i=0;i<31000;i++)for(int j=0;j<610;j++)ret=max(ret,dp[i][j]); printf("%d\n",ret); }
B:
グラフの変なの。
連結成分ごとに、頂点数をnとするとそのなかに閉路があればn、そうでなければn-1を足していく。
グラフ理論ガチゲーは苦手だからちょっと強めに感じる。
#include<stdio.h> #include<algorithm> #include<vector> using namespace std; vector<int>g[110000]; vector<int>rev[110000]; int v[110000]; int UF[110000]; int FIND(int a){ if(UF[a]<0)return a; return UF[a]=FIND(UF[a]); } void UNION(int a,int b){ a=FIND(a);b=FIND(b);if(a==b)return; UF[a]+=UF[b];UF[b]=a; } int num; int con[110000]; void dfs(int a){ v[a]=-2; for(int i=0;i<g[a].size();i++){ if(!~v[g[a][i]]){ dfs(g[a][i]); } } con[num]=a; v[a]=num++; } int hr[110000]; int cnt; void dfs2(int a){ v[a]=1; cnt++; for(int i=0;i<rev[a].size();i++){ if(!~v[rev[a][i]]){ dfs2(rev[a][i]); } } } int main(){ int a,b; scanf("%d%d",&a,&b); for(int i=0;i<a;i++)UF[i]=-1; for(int i=0;i<b;i++){ int p,q;scanf("%d%d",&p,&q); p--;q--; g[p].push_back(q); rev[q].push_back(p); UNION(p,q); } for(int i=0;i<a;i++){ v[i]=-1; } for(int i=0;i<a;i++){ if(!~v[i]){ dfs(i); } } int ssc=0; for(int i=0;i<a;i++)v[i]=-1; for(int i=a-1;i>=0;i--){ if(!~v[con[i]]){ cnt=0; dfs2(con[i]); if(cnt>1){ hr[FIND(con[i])]=1; } } } int ret=0; for(int i=0;i<a;i++){ if(UF[i]<0){ int sz=-UF[i]; ret+=sz-1+hr[i]; } } printf("%d\n",ret); }
22nd
2279 -> 2388 (+109)
やっぱり出てちゃんと通せばレートは上がるんだなあ。
結局今回も簡単枠しか通せないのであった。壁を感じる。