A. Anniversary Cake
隨便挑兩個點切掉就好了。
#include<bits/stdc++.h> using namespace std; const int Maxn=200020; typedef long long LL; typedef pair<int,int>pi; pi a[2]; int main() { freopen("anniversary.in","r",stdin); freopen("anniversary.out","w",stdout); int w,h; scanf("%d%d",&w,&h); int x,y; for(int i=0;i<2;i++){ scanf("%d%d",&x,&y); a[i]=pi(x,y); } sort(a,a+2); //puts("ok"); if(a[0].first==a[1].first){ printf("%d %d %d %d\n",0,a[0].second,w,a[1].second); } else{ printf("%d %d %d %d\n",a[0].first,0,a[1].first,h); } return 0; }
B. Boys and Girls
分類討論構造。
#include<bits/stdc++.h> using namespace std; const int Maxn=105; typedef long long LL; typedef pair<int,int>pi; int n,x,y; string rep; void pt(int cnt,string s){ for(int i=0;i<cnt;i++){ for(int j=0;j<s.size();j++)rep.push_back(s[j]); } } bool solve(){ int t1=x+y-n,t2=x-t1,t3=y-t1; if(t1<0||t2<0||t3<0)return 0; if(!x&&!y)return 0; if((n==x&&y==0)||(n==y&&x==0)){ if(n==y){ for(int i=0;i<n;i++)pt(1,"G");//putchar('G'); } else{for(int i=0;i<n;i++)pt(1,"B");}//putchar('B');} return 1; } if(t1%2)return 0; if(t1>=4){ if(t1%4==0){ int cnt=t1/4; pt(cnt-1,"BBGG"); pt(2+t2,"B"); pt(2+t3,"G"); return 1; } else{ if(!t2&&!t3)return 0; if(t2){ pt(t2+1,"B"); pt(t3+2,"G"); for(int i=0;i<t1/2-2;i++){ if(i%2==0)pt(2,"B"); else pt(2,"G"); } pt(1,"G"); } else{ pt(t3+1,"G"); pt(t2+2,"B"); for(int i=0;i<t1/2-2;i++){ if(i%2==0)pt(2,"G"); else pt(2,"B"); } pt(1,"B"); } return 1; } } else if(t1==2){ if(t2==t3)return 0; if(t2>=t3){ pt(t2-t3+1,"B"); pt(1,"G"); pt(t3,"BG"); } else{ pt(t3-t2+1,"G"); pt(1,"B"); pt(t2,"GB"); } return 1; } else if(!t1){ if(t2!=t3)return 0; if(t2+t3!=n)return 0; for(int i=0;i<n;i++)pt(1,i&1?"B":"G");//putchar(i&1?'B':'G'); return 1; } } bool go(){ int t1=0,t2=0; for(int i=0;i<rep.size();i++){ int nxt=(i+1)%rep.size(); int bef=(i-1+rep.size())%rep.size(); if(rep[nxt]=='B'||rep[bef]=='B')t1++; if(rep[nxt]=='G'||rep[bef]=='G')t2++; } if(rep.size()!=n)return 0; if(t1!=x||t2!=y)return 0; return 1; } bool check(){ if(rep==""){ string tmp(n,'B'); for(int mask=0;mask<1<<n;mask++){ for(int j=0;j<n;j++){ if(mask>>j&1)tmp[j]='G'; else tmp[j]='B'; } if(go()){ puts("wa"); cout<<tmp<<endl; return 0; } } return 1; } return go(); } int main() { freopen("boysgirls.in","r",stdin); freopen("boysgirls.out","w",stdout); srand(time(NULL)); /* int _=1000; while(_--){ n=16; x=rand()%n,y=rand()%n; */ scanf("%d%d%d",&n,&x,&y); rep=""; if(!solve())puts("Impossible"); else { //printf("%d %d %d\n",n,x,y); //cout<<"myans="<<endl; cout<<rep<<endl; } /* if(!check()){ puts("wa"); while(1); } else puts("ok"); */ //} return 0; }
C. CodeCoder vs TopForces
將所有人按兩種rating分開排序,相鄰的之間連有向邊,那麼SCC縮點之後,剩下的圖是個競賽圖,求出拓撲序之後前面所有的點都是可達的。
#include<cstdio> #include<algorithm> using namespace std; const int N=500000; int n,i,a[N],b[N],q[N]; int g[2][N],v[2][N],nxt[2][N],ed; int vis[N],size[N],f[N],ans[N],sum,t; inline bool cmpa(int x,int y){return a[x]<a[y];} inline bool cmpb(int x,int y){return b[x]<b[y];} inline void add(int x,int y){ v[0][++ed]=y;nxt[0][ed]=g[0][x];g[0][x]=ed; v[1][ed]=x;nxt[1][ed]=g[1][y];g[1][y]=ed; } void dfs1(int x){ vis[x]=1; for(int i=g[0][x];i;i=nxt[0][i])if(!vis[v[0][i]])dfs1(v[0][i]); q[++t]=x; } void dfs2(int x,int y){ vis[x]=0;f[x]=y;size[y]++; ans[x]=sum; for(int i=g[1][x];i;i=nxt[1][i])if(vis[v[1][i]])dfs2(v[1][i],y); } int main(){ freopen("codecoder.in","r",stdin); freopen("codecoder.out","w",stdout); scanf("%d",&n); for(i=1;i<=n;i++)scanf("%d%d",&a[i],&b[i]); for(i=1;i<=n;i++)q[i]=i; sort(q+1,q+n+1,cmpa); for(i=1;i<n;i++)add(q[i],q[i+1]); sort(q+1,q+n+1,cmpb); for(i=1;i<n;i++)add(q[i],q[i+1]); for(i=1;i<=n;i++)if(!vis[i])dfs1(i); for(i=t;i;i--)if(vis[q[i]]){ dfs2(q[i],q[i]); sum+=size[q[i]]; } for(i=1;i<=n;i++)printf("%d\n",ans[i]+size[f[i]]-1); return 0; }
D. Digital Addition
從低位到高位DP即可。
#include<bits/stdc++.h> using namespace std; const int Maxn=105; typedef long long LL; typedef pair<int,int>pi; pi a[2]; int occ[3][10]={{3,0,2,0,1,1,3,0,3,1}, {5,0,7,7,2,7,7,1,7,7} ,{3,3,1,3,3,2,2,3,3,3} }; int has[10][10][10][3]; int s1[10][Maxn],s2[10][Maxn]; int n; int num[Maxn][3]; int dp[Maxn][2][16]; int rep[3][Maxn]; bool debug; struct Node{ int a,b,c; Node(){} Node(int a,int b,int c):a(a),b(b),c(c){} }pre[Maxn][2][16],pe[Maxn][2][16]; int main() { freopen("digital.in","r",stdin); freopen("digital.out","w",stdout); for(int i=0;i<10;i++) for(int j=0;j<10;j++) for(int k=0;k<10;k++){ for(int ty=0;ty<3;ty++){ has[i][j][k][ty]=occ[ty][i]|(occ[ty][j]<<1)|(occ[ty][k]<<2); } } while(scanf("%d",&n)!=EOF){ int t1=0,t2=0; for(int i=0;i<9;i++){ if(i%2==0){ for(int j=0;j<n;j++){ scanf("%d",&s1[t1][j]); } t1++; } else{ for(int j=0;j<=n;j++){ scanf("%d",&s2[t2][j]); } t2++; } } memset(num,0,sizeof num); for(int i=0;i<n;i++){ for(int j=0;j<4;j++){ num[i][0]|=s2[j][i]<<j; num[i][2]|=s2[j][i+1]<<j; } for(int j=0;j<5;j++){ num[i][1]|=s1[j][i]<<j; } } //for(int i=0;i<n;i++)printf("nm%d %d %d\n",num[i][0],num[i][1],num[i][2]); memset(dp,0,sizeof dp); dp[n][0][0]=1; for(int i=n-1;i>=0;i--) for(int j=0;j<2;j++) for(int mask=0;mask<16;mask++){ if(!dp[i+1][j][mask])continue; //printf("i=%d j=%d mask=%d\n",i,j,mask); for(int a=0;a<10;a++) for(int b=0;b<10;b++) for(int c=0;c<10;c++){ if(i==1&&j==0&&a==7&&b==4&&c==1)debug=1; else debug=0; if((a+b+j)%10!=c)continue; int nj=(a+b+j)/10,nmask=has[a][b][c][0]; int t0=has[a][b][c][0]; int t1=has[a][b][c][1]; int t2=has[a][b][c][2]|mask; //if(debug)printf("t0=%d t1=%d t2=%d\n",t0,t1,t2); if((t1!=num[i][1])||(t2!=num[i][2]))continue; dp[i][nj][nmask]=1; pre[i][nj][nmask]=Node(i+1,j,mask); pe[i][nj][nmask]=Node(a,b,c); //if(debug)printf("i+1=%d %d %d\n",i+1,nj,nmask); } } int cs=num[0][0]; if(!dp[0][0][cs]){puts("NO");} else{ int curj=0,curmask=cs; for(int i=0;i<n;i++){ rep[0][i]=pe[i][curj][curmask].a; rep[1][i]=pe[i][curj][curmask].b; rep[2][i]=pe[i][curj][curmask].c; Node tmp=pre[i][curj][curmask]; curj=tmp.b; curmask=tmp.c; } for(int i=0;i<3;i++){ for(int j=0;j<n;j++)printf("%d",rep[i][j]); puts(""); } } } return 0; }
E. Easy Reading
注意到$n\times m\leq 10^5$,那麼有$\min(n,m)\leq\sqrt{10^5}$,不妨假設$n\leq m$,剩下的情況可以通過旋轉來保證$n\leq m$。
列舉左端點,往右延伸右端點,維護經過的點的個數,直到找到第一個使得經過的點的個數不小於給定圖案裡點的個數的右端點為止。
這個過程可以通過two-pointer實現,同時維護目前框住矩形的上下左右邊界,以及每一行的hash值,當點數相等、矩形邊界相等時,暴力掃描每一行判斷是否匹配即可。
時間複雜度$O(|S|\sqrt{nm})$。
#include<cstdio> #include<algorithm> #include<cstring> #include<map> using namespace std; const int N=300010,M=500,Delta=150000; const int S=233,P=1000000007; typedef pair<int,int>PI; typedef long long ll; int len,i,j; int cnt,q[N]; int L,R,U,D,all; map<int,int>cx,cy; map<PI,int>vis; int lazy,invlazy; int val[N]; int st,en; PI que[N]; int ql,qr; char s[N]; int inv,po[N]; int goal[M]; int weight,height,totalX; inline int power(int a,int b){ int t=1; for(;b;b>>=1,a=1LL*a*a%P)if(b&1)t=1LL*t*a%P; return t; } inline char read(){ char x; while((x=getchar())!='.'&&x!='X'); return x=='X'; } void init(){ int n,m; scanf("%d%d",&n,&m); int cnt=n*m; static int h[M]; int L=N,R=-N,U=N,D=-N; if(n<m){ for(int i=1;i<=n;i++){ h[i]=0; for(int j=1;j<=m;j++){ int o=read(); h[i]=(1LL*o*po[j-1]+h[i])%P; if(o==1){ totalX++; L=min(L,j); R=max(R,j); U=min(U,i); D=max(D,i); } } //printf("hash[%d]=%d\n",i,h[i]); } }else{ for(int i=1;i<=len;i++){ if(s[i]=='l')s[i]='u'; else if(s[i]=='r')s[i]='d'; else if(s[i]=='u')s[i]='l'; else if(s[i]=='d')s[i]='r'; } for(int i=1;i<=m;i++)h[i]=0; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ int o=read(); h[j]=(1LL*o*po[i-1]+h[j])%P; if(o==1){ totalX++; L=min(L,i); R=max(R,i); U=min(U,j); D=max(D,j); } } } } weight=R-L+1; height=D-U+1; int mul=1; for(int i=1;i<L;i++)mul=1LL*mul*inv%P; //printf("%d %d\n",U,D); for(int i=U;i<=D;i++)goal[i-U+1]=1LL*h[i]*mul%P; } inline bool canmatch(){ /*printf("lazy=%d\n",lazy); for(int i=1;i<=height;i++){ printf("val=%d,goal=%d\n",val[st+i-1],goal[i]); }*/ for(int i=1;i<=height;i++){ if(1LL*val[st+i-1]*lazy%P!=goal[i])return 0; } return 1; } inline void add(char dir){ PI t=que[qr]; if(dir=='l')t.second--; if(dir=='r')t.second++; if(dir=='u')t.first--; if(dir=='d')t.first++; que[++qr]=t; int x=t.first,y=t.second; if(x<U){ val[--st]=0; U--; }else if(x>D){ val[++en]=0; D++; } if(y<L){ lazy=1LL*lazy*S%P; invlazy=1LL*invlazy*inv%P; L--; }else if(y>R){ R++; } cx[x]++; cy[y]++; if(!vis[t]){ val[st+x-U]=(1LL*po[y-L]*invlazy+val[st+x-U])%P; all++; } vis[t]++; } inline void del(){ PI t=que[ql++]; int x=t.first,y=t.second; cx[x]--; cy[y]--; vis[t]--; if(!vis[t]){ val[st+x-U]=(1LL*(P-po[y-L])*invlazy+val[st+x-U])%P; all--; } if(!cx[x]){ if(x==U){ st++; U++; }else if(x==D){ en--; D--; } } if(!cy[y]){ if(y==L){ L++; lazy=1LL*lazy*inv%P; invlazy=1LL*invlazy*S%P; }else if(y==R){ R--; } } } void solve(){ if(height==1&&weight==1){ for(i=1;i<=len;i++)if(s[i]!='l'&&s[i]!='r'&&s[i]!='u'&&s[i]!='d'){ puts("YES"); printf("%d %d\n",i,i); return; } puts("NO"); return; } cnt=0; for(i=1;i<=len;i++) if(s[i]=='l'||s[i]=='r'||s[i]=='u'||s[i]=='d') q[++cnt]=i; if(!cnt){ puts("NO"); return; } L=R=U=D=0; all=1; val[st=en=Delta]=po[0]; cx[0]=1; cy[0]=1; vis[PI(0,0)]=1; lazy=invlazy=1; que[ql=qr=1]=PI(0,0); //now have [1,0] add(s[q[1]]); //now have [1,1] for(i=j=1;i<=cnt;i++){ //[i,j] if(i>1){ del(); } while(j<cnt&&all<totalX){ j++; add(s[q[j]]); } if(all<totalX){ puts("NO"); return; } // printf("%d %d %d\n",q[i],q[j],all); if(all>totalX)continue; if(R-L+1==weight&&D-U+1==height){ //printf("%d %d %d %d %d %d %d\n",q[i],q[j],all,U,D,L,R); //if(q[i]==3&&q[j]==41){ // for(int k=ql;k<=qr;k++)printf("->%d %d\n",que[k].first,que[k].second); //} if(!canmatch())continue; puts("YES"); printf("%d %d\n",q[i],q[j]); return; } } puts("NO"); } int main(){ freopen("easy.in","r",stdin); freopen("easy.out","w",stdout); fgets(s,100,stdin); sscanf(s,"%d",&len); fgets(s+1,100010,stdin); inv=power(S,P-2); for(i=po[0]=1;i<N;i++)po[i]=1LL*po[i-1]*S%P; //printf("po=%d,%d,%d,%d\n",po[0],po[1],po[2],po[3]); init(); //puts("OK"); //printf("%d %d\n",height,weight); solve(); return 0; }
F. Folding
按題意模擬即可。
#include <bits/stdc++.h> using namespace std ; const int INF = 2e9 ; int W , H , w , h ; int get ( int x , int y ) { if ( x == y ) return 0 ; int t = 0 ; while ( x > 2 * y ) x = ( x + 1 ) / 2 , ++ t ; return t + 1 ; } void solve () { int ans = INF ; if ( W >= w && H >= h ) ans = min ( get ( W , w ) + get ( H , h ) , ans ) ; if ( W >= h && H >= w ) ans = min ( get ( W , h ) + get ( H , w ) , ans ) ; if ( ans == INF ) printf ( "-1\n" ) ; else printf ( "%d\n" , ans ) ; } int main () { freopen("folding.in","r",stdin); freopen("folding.out","w",stdout); while ( ~scanf ( "%d%d%d%d" , &W , &H , &w , &h ) ) solve () ; return 0 ; }
G. Gangsters in Central City
將根去掉,那麼原樹將分裂成若干子樹,每個子樹如果有強盜,那麼就要割掉它們的lca,否則不需要割,線段樹維護區間關鍵點的lca即可。
時間複雜度$O(m\log^2n)$。
#include<cstdio> #include<algorithm> using namespace std; const int N=100010; int n,m,i,x,g[N],v[N],nxt[N],ed; int f[N],d[N],size[N],leaf[N],son[N],top[N]; int st[N],en[N],dfn,from[N]; int ans0,ans1,all; bool vip[N]; char op[5]; int val[262150]; inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;} void dfs(int x){ size[x]=1; leaf[x]=g[x]==0; for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){ f[v[i]]=x; d[v[i]]=d[x]+1; dfs(v[i]); size[x]+=size[v[i]]; leaf[x]+=leaf[v[i]]; if(size[v[i]]>size[son[x]])son[x]=v[i]; } } void dfs2(int x,int y){ st[x]=++dfn; top[x]=y; if(son[x])dfs2(son[x],y); for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x]&&v[i]!=f[x])dfs2(v[i],v[i]); en[x]=dfn; } void dfs3(int x,int y){ from[x]=y; for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x])dfs3(v[i],y); } inline int lca(int x,int y){ for(;top[x]!=top[y];x=f[top[x]])if(d[top[x]]<d[top[y]])swap(x,y); return d[x]<d[y]?x:y; } inline int merge(int x,int y){ if(!x||!y)return x+y; return lca(x,y); } void change(int x,int a,int b,int c,int p){ if(a==b){val[x]=p;return;} int mid=(a+b)>>1; if(c<=mid)change(x<<1,a,mid,c,p);else change(x<<1|1,mid+1,b,c,p); val[x]=merge(val[x<<1],val[x<<1|1]); } int ask(int x,int a,int b,int c,int d){ if(c<=a&&b<=d)return val[x]; int mid=(a+b)>>1,t=0; if(c<=mid)t=ask(x<<1,a,mid,c,d); if(d>mid)t=merge(t,ask(x<<1|1,mid+1,b,c,d)); return t; } inline void ins(int x){ if(vip[x])return; vip[x]=1; all++; int l=st[from[x]],r=en[from[x]]; int z=ask(1,1,n,l,r); if(z)ans0--,ans1-=leaf[z]; change(1,1,n,st[x],x); z=ask(1,1,n,l,r); if(z)ans0++,ans1+=leaf[z]; } inline void del(int x){ if(!vip[x])return; vip[x]=0; all--; int l=st[from[x]],r=en[from[x]]; int z=ask(1,1,n,l,r); if(z)ans0--,ans1-=leaf[z]; change(1,1,n,st[x],0); z=ask(1,1,n,l,r); if(z)ans0++,ans1+=leaf[z]; } int main(){ freopen("gangsters.in","r",stdin); freopen("gangsters.out","w",stdout); scanf("%d%d",&n,&m); for(i=2;i<=n;i++)scanf("%d",&x),add(x,i); dfs(1); dfs2(1,1); for(i=g[1];i;i=nxt[i])dfs3(v[i],v[i]); while(m--){ scanf("%s%d",op,&x); if(op[0]=='+')ins(x); else del(x); printf("%d %d\n",ans0,ans1-all); } return 0; }
H. Hard Cuts
留坑。
I. Integral Polygons
預處理出字首叉積和,然後將叉積以及點的座標都模2,列舉右端點,暴力列舉左端點的座標以及叉積值即可。
時間複雜度$O(n)$。
#include<bits/stdc++.h> using namespace std; const int Maxn=200020; typedef long long LL; int n; int cnt[2][2][2]; int x[Maxn],y[Maxn]; int main() { freopen("integral.in","r",stdin); freopen("integral.out","w",stdout); while(scanf("%d",&n)!=EOF){ int sum=0; for(int i=0;i<n;i++){ scanf("%d%d",x+i,y+i); x[i]%=2;if(x[i]<0)x[i]+=2; y[i]%=2;if(y[i]<0)y[i]+=2; } memset(cnt,0,sizeof cnt); LL ans=0; for(int i=0;i<n;i++){ int nxt=(i+1)%n; sum=(sum+x[nxt]*y[i]-x[i]*y[nxt])%2; if(sum<0)sum+=2; //if(nxt){ for(int j=0;j<2;j++){ for(int k=0;k<2;k++){ for(int bef=0;bef<2;bef++){ int tmpsum=((x[nxt]*j+y[nxt]*k)%2)^(sum^bef); if(tmpsum%2==0){ ans+=cnt[j][k][bef]; } } } //} } //printf("i=%d ans=%lld\n",i,ans); cnt[y[nxt]][x[nxt]][sum]++; } if(sum)puts("0"); else printf("%lld\n",ans-n); } return 0; }
J. Java2016
不斷生成隨機數取$\max$即可以幾乎為$100%$的概率得到$1$,然後可以得到$2,4,8,16,32,64,128$,將$c$二進位制拆分即可。
#include<cstdio> int n,i,flag; int main(){ freopen("java2016.in","r",stdin); freopen("java2016.out","w",stdout); scanf("%d",&n); if(!n)return puts("?/?/?"),0; puts("a=? max ?"); for(i=1;i<18;i++)printf("%c=%c max %c\n",'a'+i,'a'+i-1,'a'+i-1); printf("%c=%c/%c\n",'a'+18,'a'+17,'a'+17); for(i=19;i<26;i++)printf("%c=%c+%c\n",'a'+i,'a'+i-1,'a'+i-1); for(i=0;i<8;i++)if(n>>i&1){ if(flag)putchar('+'); flag=1; putchar(i+'a'+18); } return 0; }
K. King’s Heir
按題意模擬即可。
#include<cstdio> #include<algorithm> using namespace std; const int N=500000; int death,n,i,now,ans,id; int s[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}; int get(){ int d,m,y; scanf("%d%d%d",&d,&m,&y); int t=y*365+d+s[m-1]; return t; } int main(){ freopen("king.in","r",stdin); freopen("king.out","w",stdout); for(i=1;i<=12;i++)s[i]+=s[i-1]; death=get(); scanf("%d",&n); ans=-1; id=-1; for(i=1;i<=n;i++){ now=get(); if(death-now>=365*18&&now>ans)ans=now,id=i; } printf("%d",id); return 0; }
總結:
- J題發現題讀錯之後集體放棄了思考,以致於過了E的情況下還只有9題,下次要注意。