bzoj复习
bzoj复习
bzoj复习
Table of Contents
1 1001
此题其实是一道网络流的裸题,不过也可以用最短路解决。
此处有网络流和dijstra的code。
#include <cstdio> #include <cstring> const int M=1000*1000*6+20,N=1000*1000+10; char inb[1<<16],*ins=inb,*ine=inb; #define getc() ((ins==ine&&(ine=(ins=inb)+fread(inb,1,1<<16,stdin),ins==ine))?EOF:*ins++) inline int geti() { register int a; register char c; while(c=getc(),c<'0');a=c-'0'; while(c=getc(),'-'<c)a=(a<<3)+(a<<1)+c-'0'; return a; } int to[M],nxt[M],C[M],head[N],tote; #define adde(a,b,c) {\ to[tote]=b,nxt[tote]=head[a],C[tote]=c;\ head[a]=tote++;\ } #define min(a,b) (a<b?a:b) int S,T,d[N],dt[N]; int dfs(int u,int flow) { if(u==T||!flow) return flow; int r=0,t,v; for(int i=head[u];~i;i=nxt[i]) if(d[v=to[i]]+1==d[u]&&C[i]) { t=dfs(v,min(C[i],flow)); r+=t,flow-=t; C[i]-=t,C[i^1]+=t; if(!flow||d[S]>T) return r; } if(!(--dt[d[u]])) d[S]=T+1; ++dt[++d[u]]; return r; } inline int SAP() { int *l=dt,*r=dt; register int ans=0,i; *r++=T; d[T]=1; while(l<r) { for(i=head[*l];~i;i=nxt[i]) if(!d[to[i]]) d[*r++=to[i]]=d[*l]+1; ++l; } memset(dt,0,T+2<<2); for(i=S;i<=T;++i) ++dt[d[i]]; while(d[S]<T+1) ans+=dfs(S,0x7f7f7f7f); return ans; } int main() { register int n=geti(),m=geti(),i,j,k; S=1,T=n*m; memset(head,-1,T+1<<2); for(i=1;i<=n;++i) for(j=1;j^m;++j) { k=geti(); adde((i-1)*m+j,(i-1)*m+j+1,k); adde((i-1)*m+j+1,(i-1)*m+j,k); } for(i=1;i^n;++i) for(j=1;j<=m;++j) { k=geti(); adde((i-1)*m+j,i*m+j,k); adde(i*m+j,(i-1)*m+j,k); } for(i=1;i^n;++i) for(j=1;j^m;++j) { k=geti(); adde((i-1)*m+j,i*m+j+1,k); adde(i*m+j+1,(i-1)*m+j,k); } printf("%d\n",SAP()); return 0; }
#include <queue> #include <cstdio> #include <cstring> using namespace std; char inb[1<<16],*ins=inb,*ine=inb; #define getc() ((ins==ine&&(ine=(ins=inb)+fread(inb,1,1<<16,stdin),ins==ine))?EOF:*ins++) inline int geti() { register int a; register char c; while(c=getc(),c<'0');a=c-'0'; while(c=getc(),'-'<c)a=(a<<3)+(a<<1)+c-'0'; return a; } #define N 2000000 struct E{int to,v;E*nxt;}CD[N*5],*cd=CD,*head[N]; #define adde(a,b,c) (cd->v=c,cd->to=b,cd->nxt=head[a],head[a]=cd++) int d[N]; #define pr pair<int,int> priority_queue< pr, vector< pr >,greater < pr > >heap; int main() { int n,m; scanf("%d%d",&n,&m); register int S=0,T=(n-1)*(m-1)*2+1; if(n==1|m==1) { register int ans=1<<30,a; while(scanf("%d",&a)==1) if(a<ans) ans=a; printf("%d\n",ans); return 0; } register int e=1,f=2,i,j,a,b,c; for(i=0;i^n;++i) for(j=1;j^m;++j) { c=geti(); if(!i) a=T,b=f,f+=2; else if(i==n-1) a=e,b=0,e+=2; else a=e,b=f,e+=2,f+=2; adde(a,b,c);adde(b,a,c); } e=1,f=2; for(i=1;i^n;++i) for(j=0;j^m;++j) { c=geti(); if(!j) a=0,b=e,e+=2; else if(j==m-1) a=f,b=T,f+=2; else a=e,b=f,e+=2,f+=2; adde(a,b,c);adde(b,a,c); } e=1,f=2; for(i=1;i^n;++i) for(j=1;j^m;++j) { c=geti(); adde(e,f,c);adde(f,e,c); e+=2,f+=2; } memset(d,127,sizeof d); while(!heap.empty()) heap.pop(); heap.push(make_pair(*d=0,0)); E*it; while(!heap.empty()) { a=heap.top().second,c=heap.top().first; heap.pop(); if(c^d[a]) continue; for(it=head[a];it;it=it->nxt) if(c+it->v<d[b=it->to]) heap.push(make_pair(d[b]=c+it->v,b)); } printf("%d\n",d[T]); return 0; }
2 1002
此题的推导比较麻烦,用基尔霍矩阵计算生成树个数,经过一系列推导可以得到$F(n) = 3 * F(n - 1) - F(n - 2) + 2$。
具体推导可见http://vfleaking.blog.163.com/blog/static/17480763420119685112649/。
#include <cstdio> int a[20],b[20],c[20],n; #define ba 1000000 int main() { scanf("%d",&n); if(n<3) return puts(n<2?"1":"5"),0; register int i,la=1,lb=1,lc=1; *a=1,*b=5; n-=2; while(n--) { //c=3*b-a+2 for(i=0;i<lb;++i) c[i]=b[i]*3; for(i=0;i<lb;++i) c[i+1]+=c[i]/ba,c[i]%=ba; for(lc=lb;c[lc];++lc); *c+=2; for(i=0;i<lc;++i) { c[i]-=a[i]; if(c[i]<0) --c[i+1],c[i]+=ba; } while(!c[lc-1]) --lc; for(i=0;i<lb;++i)a[i]=b[i];la=lb; for(i=0;i<lc;++i)b[i]=c[i];lb=lc; } printf("%d",c[lc-1]); for(i=lc-2;~i;--i) printf("%06d",c[i]); return 0; }
3 1003
此题比较简单,就是一个dp+最短路。
#include <queue> #include <cstdio> #include <cstring> using namespace std; inline int geti() { register int a; register char c; while(c=getchar(),c<'0');a=c-'0'; while(c=getchar(),'-'<c)a=(a<<3)+(a<<1)+c-'0'; return a; } int dp[102],c[102][102],vis[102],d[21]; struct E{int to,v;E*nxt;}CD[100*100+2],*cd=CD,*head[102]; inline void cmin(int&a,int b){b<a?a=b:1;} #define pr pair<int,int> priority_queue< pr, vector< pr >,greater < pr > >heap; inline int dijstra(int sta,int t) { memset(d,127,sizeof d); while(!heap.empty()) heap.pop(); heap.push(make_pair(*d=0,0)); int s,dis; E*it; while(!heap.empty()) { s=heap.top().second,dis=heap.top().first; heap.pop(); if(dis^d[s]) continue; for(it=head[s];it;it=it->nxt) if(!(sta&(1<<it->to))&&dis+it->v<d[it->to]) heap.push(make_pair(d[it->to]=dis+it->v,it->to)); } return (d[t]^0x7f7f7f7f)?d[t]:-1; } int main() { register int n=geti(),m=geti(),k=geti(),e=geti(),i,j,x; while(e--) { i=geti()-1,j=geti()-1,x=geti(); cd->v=x,cd->to=j,cd->nxt=head[i],head[i]=cd++; cd->v=x,cd->to=i,cd->nxt=head[j],head[j]=cd++; } for(e=geti();e;--e) { x=geti()-1,i=geti(),j=geti(); for(;i<=j;++i)vis[i]|=1<<x; } memset(c,-1,sizeof c); for(i=1;i<=n;++i) { x=0; for(j=i;j<=n;++j) { x|=vis[j]; if((c[i][j]=dijstra(x,m-1))<0) break; } } dp[0]=0,dp[1]=c[1][1]; for(i=2;i<=n;++i) { dp[i]=(~c[1][i])?(c[1][i]*i):0x7f7f7f7f; for(j=i;j;--j) if(~c[j][i]) cmin(dp[i],dp[j-1]+k+(i-j+1)*c[j][i]); else break; } printf("%d\n",dp[n]); return 0; }
4 1004
这是一道群论的裸题,需要用到burnside定理得出公式$ans=\segma Cal(Changei) * |G|-1$。
#include <cstdio> #include <cstring> inline int geti() { register int a; register char c; while(c=getchar(),c<'0');a=c-'0'; while(c=getchar(),'-'<c)a=(a<<3)+(a<<1)+c-'0'; return a; } int dp[22][22][22],change[100][61],vis[61],vis_clock,d[61]; int sr,sb,sg,n,p; #define inc(a,b) for((a)+=(b);(a)>=p;(a)-=p) inline int Cal(int*a) { memset(dp,0,sizeof dp); register int s=0,i,j,k,t; ++vis_clock; for(i=1;i<=n;++i) if(vis[i]^vis_clock) { d[s]=0; for(j=i;vis[j]^vis_clock;j=a[j]) vis[j]=vis_clock,++d[s]; ++s; } dp[0][0][0]=1; for(--s;~s;--s) for(t=d[s],i=sr;~i;--i) for(j=sb;~j;--j) for(k=sg;~k;--k) { if(i>=t) inc(dp[i][j][k],dp[i-t][j][k]); if(j>=t) inc(dp[i][j][k],dp[i][j-t][k]); if(k>=t) inc(dp[i][j][k],dp[i][j][k-t]); } return dp[sr][sb][sg]; } int main() { sr=geti(),sb=geti(),sg=geti(); register int m=geti(),i,j; p=geti(); n=sr+sb+sg; for(i=0;i<m;++i) for(j=1;j<=n;++j) change[i][j]=geti(); for(i=1;i<=n;++i) change[m][i]=i; ++m; int ans=0; for(i=0;i<m;++i) for(ans+=Cal(change[i]);ans>=p;ans-=p); for(i=m,j=p-2;j;j>>=1,i=i*i%p)if(j&1)ans=ans*i%p; printf("%d\n",ans); return 0; }
5 1005
此题需要用到prufer序列,之后再结合组合数就好了。
#include <cstdio> #define SIZE 169 #define ba 10000 const int p[SIZE] = { 0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73, 79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191, 193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311, 313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439, 443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577, 587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709, 719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857, 859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997 }; inline int geti() { register int a; register char c,f=0; while(c=getchar(),c<'0')f|=c=='-';a=c-'0'; while(c=getchar(),'-'<c)a=(a<<3)+(a<<1)+c-'0'; return f?-a:a; } int e[SIZE],Ans[3000]; inline void Fac(const int &n,const bool&k) { register int i,j; for(i=1;i^SIZE;++i) for(j=p[i];j<=n;j*=p[i]) k?(e[i]+=n/j):(e[i]-=n/j); } int main() { register int n=geti(),i,len=n-2,m=0,t; for(i=0;i<n;++i) { t=geti(); if(!t||len<t-1) return puts("0"),0; if(t<0) {++m;continue;}--t; Fac(len,1); Fac(t,0); Fac(len-t,0); len-=t; } if(len) { for(i=1;(i^SIZE)&&1<m;++i) while(!(m%p[i])) m/=p[i],e[i]+=len; } Ans[1]=len=1; for(i=1;i^SIZE;++i) while(e[i]--) { for(t=1;t<=len;++t) Ans[t]*=p[i]; for(t=1;t<=len;++t) if(Ans[t]>=ba) Ans[t+1]+=Ans[t]/ba,Ans[t]%=ba; while(Ans[len+1]) { if(Ans[len]>=ba) Ans[len+1]+=Ans[len]/ba,Ans[len]%=ba; ++len; } } for(printf("%d",Ans[len]),i=len-1;i;--i) printf("%04d",Ans[i]); return 0; }
6 1006
此题请查看cdq的论文,此处为$O(n+m)$解法。
#include <cstdio> #include <cstring> inline int geti() { register int a; register char c; while(c=getchar(),c<'0');a=c-'0'; while(c=getchar(),'-'<c)a=(a<<3)+(a<<1)+c-'0'; return a; } #define N 10005 #define M 3000005 struct E{int to;E*nxt;}CD[M],*cd=CD,*head[N],*st[N]; inline void adde(int a,int b) {cd->to=b,cd->nxt=head[a],head[a]=cd++;} inline void ins(int a,int b) {cd->to=b,cd->nxt=st[a],st[a]=cd++;} int d[N],col[N],q[N],vis[N]; int main() { #ifndef ONLINE_JUDGE freopen("1006.in","r",stdin); freopen("1006.out","w",stdout); #endif register int n=geti(),m=geti(),i,j,mx,v; E*it; while(m--) adde(i=geti(),j=geti()),adde(j,i); mx=m=0; for(i=1;i<=n;++i) ins(0,i); while(m<n) { if(!st[mx]) {--mx; continue;} if(vis[st[mx]->to]) {st[mx]=st[mx]->nxt; continue;} v=st[mx]->to; vis[v]=1; q[m++]=v; st[mx]=st[mx]->nxt; for(it=head[v];it;it=it->nxt) if(!vis[j=it->to]) { (++d[j]>mx)?mx=d[j]:1; ins(d[j],j); } } memset(vis,0,sizeof vis); for(mx=0,i=0;i<n;++i) { v=q[i]; for(it=head[v];it;it=it->nxt) vis[col[it->to]]=v; for(j=1;;++j)if(vis[j]^v)break; if((col[v]=j)>mx) mx=j; } printf("%d\n",mx); return 0; }
7 1007
一道比较裸的凸包,网传可以用半平面交写,但我不会。
#include <cstdio> #include <algorithm> char inb[1<<16],*ins=inb,*ine=inb; #define getc() ((ins>=ine&&(ine=(ins=inb)+fread(inb,1,1<<16,stdin),ins>=ine))?EOF:*ins++) inline int geti() { register int a; register char c,f=0; while(c=getc(),c<'0')f|=c=='-';a=c-'0'; while(c=getc(),'-'<c)a=(a<<3)+(a<<1)+c-'0'; return f?-a:a; } #define N 50005 struct D{int a,b,id;}p[N],sta[N]; inline bool operator < (const D&x,const D&y){return (x.a^y.a)?x.a<y.a:x.b<y.b;} bool ans[N]; char oub[N<<3],ous[10],*oue=oub; inline void outi(int x) { register char tp=0; while(x)ous[++tp]=x%10,x/=10; for(;tp;--tp)*oue++=ous[tp]+'0'; *oue++=' '; } int main() { #ifndef ONLINE_JUDGE freopen("1007.in","r",stdin); freopen("1007.out","w",stdout); #endif register int n=geti(),i,tp; register D x; for(i=1;i<=n;++i){ p[i].a=geti(); p[i].b=geti(); p[i].id=i; } std::sort(p+1,p+n+1); sta[tp=0].a=0x7f7f7f7f; for(i=1;i<=n;++i) { for(x=p[i];tp;) { if(sta[tp].a==x.a) --tp; if(1<tp&&(sta[tp-1].b-x.b+0LL)*(sta[tp].a-sta[tp-1].a+0LL)<=(sta[tp-1].b-sta[tp].b+0LL)*(x.a-sta[tp-1].a+0LL))--tp; else break; } sta[++tp]=x; } for(i=1;i<=tp;++i)ans[sta[i].id]=1; for(i=1;i<=n;++i)if(ans[i])outi(i); fwrite(oub,1,oue-oub,stdout); return 0; }
8 1008
此题比较简单,用总数减去不可能越狱的情况数就是答案。 不可能的情况有$m*(m-1)n-1$,这样就可以得到答案了。
#include <cstdio> const long long mo=100003; inline long long pow(long long b,long long n) { register long long r=1LL; for(;n;n>>=1,b=b*b%mo) if(n&1) r=r*b%mo; return r; } int main() { long long n,m,ans; scanf("%lld%lld",&m,&n); m%=mo; ans=pow(m,n); ans-=m*pow(m-1,n-1); ans%=mo; if(ans<0) ans+=mo; printf("%lld\n",ans); return 0; }
9 1009
此题是一道比较简单的题,用kmp求出下一步的转移,之后矩阵快速幂就好了。
#include <cstdio> int n,m,mo,a[25][25],b[25][25],c[25][25],nxt[25]; char s[25]; #define inc(a,b) for(a+=b;a>=mo;a-=mo) inline void mul(int (&x)[25][25],int (&y)[25][25]) { register int i,j,k; for(i=0;i<m;++i) for(j=0;j<m;++j) { c[i][j]=0; for(k=0;k<m;++k) c[i][j]=(c[i][j]+x[i][k]*y[k][j])%mo; } for(i=0;i<m;++i) for(j=0;j<m;++j) x[i][j]=c[i][j]; } int main() { register int i,j=0,t; for(scanf("%d%d%d%s",&n,&m,&mo,s+1),i=2;i<=m;++i) { while(j&&(s[j+1]^s[i]))j=nxt[j]; nxt[i]=(s[i]==s[j+1])?(++j):j; } for(i=0;i<m;++i) for(j=0;j<10;++j) { for(t=i;t&&(s[t+1]^j+'0');t=nxt[t]); if(((s[t+1]==j+'0')?++t:t)^m)++b[t][i]<mo?1:b[t][i]=0; } for(i=0;i<m;++i)a[i][i]=1; for(;n;n>>=1,mul(b,b))if(n&1)mul(a,b); for(t=0,i=0;i<m;++i)inc(t,a[i][0]); return printf("%d\n",t),0; }
10 1010
此题是一道斜率优化的裸题,比较简单。
#include <cstdio> inline int geti() { register int a; register char c,f=0; while(c=getchar(),c<'0')f|=c=='-';a=c-'0'; while(c=getchar(),'-'<c)a=(a<<3)+(a<<1)+c-'0'; return f?-a:a; } #define N 50005 long long g[N],dp[N],C; int q[N]; inline long long S(int i,int j){return (g[i]-g[j])<<1;} inline long long G(int i,int j){return dp[i]-dp[j]+(g[i]-g[j])*(g[i]+g[j]+(C<<1));} int main() { register int n=geti(),i,j,l=1,r=1; C=geti()+1; register long long s=0; q[1]=0; for(i=1;i<=n;++i) { s+=geti(); g[i]=s+i; while(l<r&&G(q[l+1],q[l])<=S(q[l+1],q[l])*g[i])++l; j=q[l]; dp[i]=dp[j]+(g[i]-g[j]-C)*(g[i]-g[j]-C); while(l<r&&G(i,q[r])*S(q[r],q[r-1])<=G(q[r],q[r-1])*S(i,q[r]))--r; q[++r]=i; } printf("%lld\n",dp[n]); return 0; }
11 1011
此题太神了,用5%的误差来优化时间。 正解t应取2000左右,不过取20也可以过。
#include <cmath> #include <cstdio> inline int geti() { register int a; register char c; while(c=getchar(),c<'0');a=c-'0'; while(c=getchar(),'-'<c)a=(a<<3)+(a<<1)+c-'0'; return a; } #define N 100002 #define t 20 int m[N]; double f[N]; int main() { register int i,j,l,r,n=geti(); double a; scanf("%lf",&a); for(i=1;i<=n;++i)m[i]=geti(),f[i]=0.0; for(i=1;i<=t;++i) for(j=1,r=floor(a*i);j<=r;++j) f[i]+=1.0*m[i]*m[j]/(i-j); for(i=t+1;i<=n;++i) { l=floor(a*(i-t)),r=floor(a*i); for(j=l+1;j<=r;++j) f[i]+=1.0*m[i]*m[j]/(i-j); f[i]+=m[i]*f[i-t]/m[i-t]*(i-t-1.0*l/2)/(i-1.0*l/2); } for(i=1;i<=n;++i) printf("%.6lf\n",f[i]); return 0; }
12 1012
此题一眼看是一道数据结构,不过仔细想想可以用单调栈搞。
#include <cstdio> #include <algorithm> inline int geti() { register int a; register char c; while(c=getchar(),c<'0');a=c-'0'; while(c=getchar(),'-'<c)a=(a<<3)+(a<<1)+c-'0'; return a; } int q[200001],v[200001]; int main() { register int m=geti(),d=geti(),t=0,x,len=0,tp=0; register char c; while(m--) { while(c=getchar(),c<'A'); x=geti(); if(c^'A') printf("%d\n",t=v[*std::lower_bound(q+1,q+tp+1,len-x+1)]); else { x=(x+t)%d; v[++len]=x; while(tp&&v[q[tp]]<=x)--tp; q[++tp]=len; } } return 0; }
13 1013
此题可以根据距离建立方程,之后guass消元就好了。
#include <cmath> #include <cstdio> #include <algorithm> int n; double a[11][11],p[11]; inline void guass() { register int i,j,k,id; register double mx,t; for(i=0;i<n;++i) { mx=-1; for(j=i;j<n;++j) if(mx<fabs(a[j][i]))mx=a[id=j][i]; if(i^id)for(j=i;j<=n;++j)std::swap(a[i][j],a[id][j]); t=a[i][i]; for(j=i+1;j<=n;++j) a[i][j]/=t; for(j=0;j<n;++j) if(i^j) for(t=a[j][i],k=1;k<=n;++k) a[j][k]-=t*a[i][k]; } } int main() { register int i,j; double t; scanf("%d",&n); for(i=0;i<n;++i)scanf("%lf",p+i); for(i=0;i<n;++i) for(j=0;j<n;++j) { scanf("%lf",&t); a[i][j]=2*(t-p[j]); a[i][n]+=t*t-p[j]*p[j]; } guass(); for(i=0;i<n;++i)printf("%.3lf%c",a[i][n],"\n "[i+1<n]); return 0; }
14 1014
此题用二分加哈希计算LCQ,之后用spaly维护哈希值还是比较简单的。
#include <cstdio> #include <cstring> inline int geti() { register int a; register char c; while(c=getchar(),c<'0');a=c-'0'; while(c=getchar(),'-'<c)a=(a<<3)+(a<<1)+c-'0'; return a; } #define ui unsigned int #define N 100050 #define ba 257 ui p[N]; struct node { ui ha; int siz; char c; node *fa,*ch[2]; }CD[N],*cd=CD,*root,*nil; inline void maintain(node*(&u)) { if(u==nil) return; u->siz=u->ch[0]->siz+u->ch[1]->siz+1; u->ha=u->ch[0]->ha+u->c*p[u->ch[0]->siz]+u->ch[1]->ha*p[u->ch[0]->siz+1]; } inline void rot(node*(&u)) { node *f=u->fa,*ff=f->fa; int d=u==f->ch[1]; if((f->ch[d]=u->ch[d^1])!=nil) f->ch[d]->fa=f; f->fa=u,u->ch[d^1]=f; if((u->fa=ff)!=nil) ff->ch[f==ff->ch[1]]=u; maintain(f);maintain(u); } inline void splay(node*(&u),node*(&target)) { while(u->fa!=target){ if(u->fa->fa==target){rot(u);break;} if((u==u->fa->ch[1])^(u->fa==u->fa->fa->ch[1]))rot(u); else rot(u->fa);rot(u); }if(target==nil)root=u; } inline node*kth(int k){ node*u=root; while(k&&u!=nil){ if(u->ch[0]->siz>=k)u=u->ch[0]; else if(u->ch[0]->siz+1==k) return u; else k-=u->ch[0]->siz+1,u=u->ch[1]; }return u; } inline void ins(int k,char ch) { node *l=kth(k); cd->c=ch; cd->ch[0]=nil,cd->ch[1]=l->ch[1]; cd->fa=l,cd->ch[1]->fa=cd; l->ch[1]=cd; maintain(cd); while(l!=nil) {maintain(l);l=l->fa;} ++cd; } inline void upd(int k,char ch){ node*u=kth(k);u->c=ch; while(u!=nil){maintain(u);u=u->fa;} } inline ui quy(int l,int r){ node*lu=kth(l-1),*ru=kth(r+1); splay(lu,nil);splay(ru,lu); return ru->ch[0]->ha; } char initstring[N]; node*build(int l,int r){ if(l>r)return nil; int m=l+r>>1;node*u=cd++; u->c=initstring[m]; if((u->ch[0]=build(l,m-1))!=nil)u->ch[0]->fa=u; if((u->ch[1]=build(m+1,r))!=nil)u->ch[1]->fa=u; maintain(u);return u; } int main() { initstring[1]='~'; scanf("%s",initstring+2); register int cl=strlen(initstring+2),i,j,mi,l,r,an,m; for(*p=i=1;i^N;++i)p[i]=p[i-1]*ba; initstring[cl+2]='!'; cd->fa=cd->ch[0]=cd->ch[1]=cd; cd->ha=cd->siz=cd->c=0;nil=cd++; root=build(1,cl+2);root->fa=nil; register char ch; for(m=geti();m;--m){ while(ch=getchar(),ch<'A'); if(ch=='Q'){ i=geti()+1,j=geti()+1; if(kth(i)->c!=kth(j)->c){puts("0");continue;} for(an=l=1,r=cl-(i<j?j:i)+2;l<=r;){ mi=l+r>>1; if(quy(i,i+mi-1)==quy(j,j+mi-1))l=(an=mi)+1; else r=mi-1; }printf("%d\n",an); }else{ j=ch=='R';cl+=j^1; i=geti()+1;while(ch=getchar(),ch<'a'); j?upd(i,ch):ins(i,ch); } }return 0;
15 1015
此题用并查集离线搞一下就好了。
#include <cstdio> inline int geti() { register int a; register char c; while(c=getchar(),c<'0');a=c-'0'; while(c=getchar(),'-'<c)a=(a<<3)+(a<<1)+c-'0'; return a; } #define N 400005 int f[N],blo,d[N],ANS[N]; bool mark[N],can[N]; inline int gf(int u){ register int en; for(en=u;f[en]^en;en=f[en]); for(register int t;u^en;t=f[u],f[u]=en,u=t); return en; } struct E{int to;E*nt;}CD[N],*cd=CD,*hd[N]; #define adde(a,b) (cd->to=b,cd->nt=hd[a],hd[a]=cd++) inline void ins(int u) { register int v; for(register E*it=hd[u];it;it=it->nt) if(can[it->to]&&(gf(u)^(v=gf(it->to)))) --blo,f[v]=gf(u); } int main() { register int n=geti(),m=geti(),i,a,b; for(i=0;i<n;++i)f[i]=i; while(m--){a=geti(),b=geti();adde(a,b),adde(b,a);} register int*ans,*t=d; for(i=0,m=geti();i<m;++i)mark[*t++=geti()]=1; for(i=0;i<n;++i) if(!mark[i])++blo,can[i]=1,ins(i); ans=ANS+m; *ans--=blo; for(i=m;i;--i) { can[a=*--t]=1; ++blo;ins(a); *ans--=blo; } for(i=0;i<=m;++i)printf("%d\n",*++ans); return 0; }
16 1016
此题需要用到关于最小生成树的一些基本性质哦。
由Kruskal算法不难得出对于一个图的不同最小生成树,其同一边权的边数相同。
这样我们就可以得出此题解法了。
#include <cstdio> #include <cstring> #include <algorithm> inline int geti() { register int a; register char c; while(c=getchar(),c<'0');a=c-'0'; while(c=getchar(),'-'<c)a=(a<<3)+(a<<1)+c-'0'; return a; } #define mo 31011 struct E{int u,v,w;}e[1002]; inline bool operator < (const E&a,const E&b){return a.w<b.w;} int L[1002],R[1002],C[1002],f[102],sum,x; inline int gf(int u) { while(f[u]^u)u=f[u]; return u; } void dfs(int cur,int t) { if(R[x]<cur){sum+=t==C[x];return;} int p=gf(e[cur].u),q=gf(e[cur].v); if(p^q){ f[p]=q; dfs(cur+1,t+1); f[p]=p,f[q]=q; } dfs(cur+1,t); } int main() { register int i,cnt=0,cedge=0,p,q; register int n=geti(),m=geti(),ans=1; for(i=0;i<m;++i)e[i].u=geti(),e[i].v=geti(),e[i].w=geti(); std::sort(e,e+m); for(i=1;i<=n;++i)f[i]=i; for(i=0;i<m;++i) { if(e[i-1].w<e[i].w)R[cnt]=i-1,R[++cnt]=i; if((p=gf(e[i].u))^(q=gf(e[i].v))) f[p]=q,++C[cnt],++cedge; }R[cnt]=m; if(cedge<n-1)return puts("0"),0; for(i=1;i<=n;++i)f[i]=i; for(x=1;x<=cnt;++x) { sum=0; dfs(L[x],0); ans=ans*sum%mo; for(i=L[x];i<=R[x];++i) if((p=gf(e[i].u))^(q=gf(e[i].v)))f[p]=q; } return printf("%d\n",ans),0; }
17 1018
此题用线段树维护联通性,每个联通只考虑用区间内的道路而不用外面的,之后一个个考虑就好了。
此题代码容易出错,要仔细些。
#include <cstdio> #include <cstring> inline int geti() { register int a; register char c; while(c=getchar(),c<'0');a=c-'0'; while(c=getchar(),'-'<c)a=(a<<3)+(a<<1)+c-'0'; return a; } #define ls u<<1 #define rs u<<1|1 #define MID int mid=l+r>>1 struct D{bool a0,a1,b0,b1,c0,c1;}C[200005]; bool edge[3][100005]; char ts[10]; void build(int u,int l,int r) { if(l>=r) { C[u].b0=C[u].b1=true; return; } MID; build(ls,l,mid);build(rs,mid+1,r); } D pluse(const D&a,const D&b,const bool&x,const bool&y) { D r; r.a0=a.a0||(a.b0&&a.b1&&x&&y&&b.a0); r.a1=b.a1||(b.b0&&b.b1&&x&&y&&a.a1); r.b0=(a.b0&&x&&b.b0)||(a.c0&&y&&b.c1); r.b1=(a.b1&&y&&b.b1)||(a.c1&&x&&b.c0); r.c0=(x&&a.b0&&b.c0)||(y&&a.c0&&b.b1); r.c1=(y&&a.b1&&b.c1)||(x&&a.c1&&b.b0); return r; } void upd(int u,int l,int r,int p) { if(l>=r) { C[u].b0=C[u].b1=true; C[u].a0=C[u].a1=C[u].c0=C[u].c1=edge[2][p]; return; } MID; if(p<=mid)upd(ls,l,mid,p);else upd(rs,mid+1,r,p); C[u]=pluse(C[ls],C[rs],edge[0][mid],edge[1][mid]); } D quy(int u,int l,int r,int x,int y) { if(l>=x&&r<=y)return C[u]; MID; if(y<=mid)return quy(ls,l,mid,x,y); if(x>mid)return quy(rs,mid+1,r,x,y); return pluse(quy(ls,l,mid,x,mid),quy(rs,mid+1,r,mid+1,y),edge[0][mid],edge[1][mid]); } int main() { register int c=geti(),r1,c1,r2,c2; build(1,1,c); register D t1,t2,t3; register bool ok; while(scanf("%s",ts)^EOF) { if(*ts=='E')break; r1=geti()-1,c1=geti(),r2=geti()-1,c2=geti(); if(c2<c1)r1^=r2^=r1^=r2,c1^=c2^=c1^=c2; if(*ts=='O') { if(r1>r2)r1^=r2^=r1^=r2,c1^=c2^=c1^=c2; if(r1<r2)edge[2][c1]=1; else edge[r1][c1]=1; upd(1,1,c,c1); } else if(*ts=='C') { if(r1>r2)r1^=r2^=r1^=r2,c1^=c2^=c1^=c2; if(r1<r2)edge[2][c1]=0; else edge[r1][c1]=0; upd(1,1,c,c1); } else { t1=quy(1,1,c,1,c1); t2=quy(1,1,c,c1,c2); t3=quy(1,1,c,c2,c); if(r1&&r2) { ok=t2.b1||(t1.a1&&t2.c0)||(t2.c1&&t3.a0); ok|=t1.a1&&t2.b0&&t3.a0; }else if(!r1^r2) { ok=t2.b0||(t1.a1&&t2.c1)||(t2.c0&&t3.a0); ok|=t1.a1&&t2.b1&&t3.a0; }else if(r1) { ok=t2.c1||(t1.a1&&t2.b0)||(t2.b1&&t3.a0); ok|=t1.a1&&t2.c0&&t3.a0; }else { ok=t2.c0||(t1.a1&&t2.b1)||(t2.b0&&t3.a0); ok|=t1.a1&&t2.c1&&t3.a0; } puts(ok?"Y":"N"); } } return 0; }
18 1066
网络流裸题,直接拆点就好了。
#include <cstdio> #include <cstring> inline int rd() { register char c; while(c=getchar(),c<'0'); return c-'0'; } char mp[22][22]; #define M 100000 int to[M],nt[M],C[M],hd[810],te; #define adde(a,b,c) (to[te]=b,nt[te]=hd[a],C[te]=c,hd[a]=te++) int d[810],dt[810],la[810],S,T,r,c,d2,hx[810],hy[810]; inline bool rid(int dx,int dy){return dx*dx+dy*dy<=d2;} int dfs(int u,int flow) { if(u==T||!flow) return flow; int r=0,t; for(int&i=la[u];~i;i=nt[i]) if(d[u]==d[to[i]]+1&&C[i]>0) { t=dfs(to[i],flow<C[i]?flow:C[i]); r+=t,flow-=t; C[i]-=t,C[i^1]+=t; if(!flow||d[S]>T+1)return r; } la[u]=hd[u]; if(!(--dt[d[u]])) d[S]=T+2; ++dt[++d[u]]; return r; } inline int SAP() { register int *l=dt,*r=dt,i; *r++=T; d[T]=1; while(l<r) { for(i=hd[*l];~i;i=nt[i]) if(!d[to[i]]) d[*r++=to[i]]=d[*l]+1; ++l; } memset(dt,0,sizeof dt); for(i=S;i<=T;++i)++dt[d[i]],la[i]=hd[i]; i=0; while(d[S]<T+2)i+=dfs(S,0x7f7f7f7f); return i; } int main() { #ifndef ONLINE_JUDGE freopen("1066.in","r",stdin); #endif int d; scanf("%d%d%d",&r,&c,&d); d2=d*d; memset(hd,-1,sizeof hd); register int i,j,k,cnt=0,tp=0; for(i=0;i<r;++i) for(j=0;j<c;++j) if(k=rd()) { ++tp; hx[tp]=i,hy[tp]=j; adde(tp,tp+1,k);adde(tp+1,tp,0); ++tp; } for(i=0;i<r;++i) { scanf("%s",mp[i]); for(j=0;j<c;++j)cnt+=mp[i][j]=='L'; } S=0,T=tp+1; for(i=1;i<tp;i+=2) { for(j=i+2;j<tp;j+=2) if(rid(hx[i]-hx[j],hy[i]-hy[j])) { adde(i+1,j,cnt),adde(j,i+1,0); adde(j+1,i,cnt),adde(i,j+1,0); } if(mp[hx[i]][hy[i]]=='L')adde(S,i,1),adde(i,S,0); if(hx[i]<d||hy[i]<d||r-hx[i]<=d||c-hy[i]<=d)adde(i+1,T,cnt),adde(T,i+1,0); } printf("%d\n",cnt-SAP()); return 0; }
19 2756
此题中我们可以很明显的发现最终形成的数具有单调性,所以可以二分。
之后用网络流进行check。
注意棋盘为奇数是要特判。
#include <cstdio> #include <cstring> char inb[1<<16],*ins=inb,*ine=inb; #define getc() ((ins==ine&&(ine=(ins=inb)+fread(inb,1,1<<16,stdin),ins==ine))?EOF:*ins++) inline int geti() { register int a; register char c,f=0; while(c=getc(),c<'0'||'9'<c)f|=c=='-';a=c-'0'; while(c=getc(),!(c<'0'||'9'<c))a=(a<<3)+(a<<1)+c-'0'; return f?-a:a; } #define N 1610 #define M 20000 const long long inf=1LL<<50; int d[N],dt[N],S,T,la[N]; int to[M],nt[M],hd[N],n,m,te; long long C[M]; int mp[42][42],idx[42][42]; inline void adde(int a,int b,long long c) { to[te]=b;nt[te]=hd[a];C[te]=c;hd[a]=te++; to[te]=a;nt[te]=hd[b];C[te]=0;hd[b]=te++; } const int dx[]={0,0,1,-1}; const int dy[]={1,-1,0,0}; long long dfs(int u,long long flow) { if(u==T||!flow)return flow; long long r=0,t; for(int&i=la[u];~i;i=nt[i]) if(d[u]==d[to[i]]+1&&C[i]>0) { t=dfs(to[i],flow<C[i]?flow:C[i]); r+=t,flow-=t; C[i]-=t,C[i^1]+=t; if(d[S]>T+1||!flow)return r; } la[u]=hd[u]; if(!(--dt[d[u]]))d[S]=T+2; ++dt[++d[u]];return r; } inline bool check(long long x) { memset(hd,-1,sizeof hd); int i,j,k,_i,_j; te=0; long long t=0,st=0; for(i=1;i<=n;++i) for(j=1;j<=m;++j) if((i+j)&1) { adde(S,idx[i][j],x-mp[i][j]); st+=x-mp[i][j]; for(k=0;k^4;++k) { _i=i+dx[k],_j=j+dy[k]; if(_i<1||_j<1||_i>n||_j>m)continue; adde(idx[i][j],idx[_i][_j],inf); } }else adde(idx[i][j],T,x-mp[i][j]); i=j=0;dt[j++]=T; memset(d,0,sizeof d); d[T]=1; while(i<j) { k=dt[i++]; for(_i=hd[k];~_i;_i=nt[_i]) if(!d[to[_i]])d[dt[j++]=to[_i]]=d[k]+1; } memset(dt,0,sizeof dt); for(i=S;i<=T;++i)++dt[d[i]],la[i]=hd[i]; while(d[S]<T+2)t+=dfs(S,inf); return st==t; } #define getskip(a) (a*n*m-s0-s1)>>1 int main() { int __=geti(),i,j,id; long long s0,s1,mv,l,r,mi,an; while(__--) { n=geti(),m=geti(); s0=s1=0LL;mv=-inf; for(id=0,i=1;i<=n;++i) for(j=1;j<=m;++j) { if((mp[i][j]=geti())>mv)mv=mp[i][j]; if((i+j)&1)s1+=mp[i][j]; else s0+=mp[i][j]; idx[i][j]=++id; } S=0,T=++id; if(n*m&1) { l=s0-s1; if(l>=mv&&check(l))printf("%lld\n",getskip(l)); else puts("-1"); }else { if(s0^s1){puts("-1");continue;} for(l=mv,r=inf;l<=r;) { mi=l+r>>1; if(check(mi))r=(an=mi)-1; else l=mi+1; } printf("%lld\n",getskip(an)); } } return 0; }
文章来自于网络,如果侵犯了您的权益,请联系站长删除!