前言
- T3想到正解然而并没有时间打。
- T1送分几乎都A了,T2概率我啥也不会。
- 我会的别人都会+别人会的我不会=考挂。
T1
- 李煜东上有用kmp求最小循环节的例题,当初看了很久,所以……
- 当然是选择Hash啦!
- 时间复杂度不超过$Theta(NlogN)$。空间复杂度$Theta(N)$。
#include<cstdio> #define ll long long using namespace std; int const N=1e6+5,p1=23333,p2=1313131,mod1=1e9+7,mod2=998244353; int n; ll ans; ll pre1[N],b1[N],pre2[N],b2[N]; inline int read(){ int ss(0),pp(1);char bb(getchar()); for(;bb<48||bb>57;bb=getchar())if(bb=='-')pp=-1; while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar(); return ss*pp; } int main(){ //freopen("1.in","r",stdin); //freopen("1.out","w",stdout); int T=read(),tp; b1[0]=b2[0]=1; for(register int i=1;i<N;++i)b1[i]=b1[i-1]*p1%mod1,b2[i]=b2[i-1]*p2%mod2; while(T--){ ans=read()-1,n=read(),tp=1; ans*=n; register char bb=getchar(),la; while(bb<'A'||bb>'Z')bb=getchar();la=bb; for(register int i=1;i<=n;++i,bb=getchar()){ pre1[i]=(pre1[i-1]*p1+bb)%mod1,pre2[i]=(pre2[i-1]*p2+bb)%mod2; if(bb!=la)tp=0; } if(tp){printf("%lld ",ans+n-1);continue;} if(!ans){ register int i=n-1; for(;i;--i) if(pre1[i]==(pre1[n]-pre1[n-i]*b1[i]%mod1+mod1)%mod1 && pre2[i]==(pre2[n]-pre2[n-i]*b2[i]%mod2+mod2)%mod2) break; printf("%d ",i); continue; } for(register int i=2,lt=n>>1;i<=lt;++i){ if(n%i)continue; int bs1=pre1[i],bs2=pre2[i]; for(register int j=i<<1;j<=n;j+=i) if((pre1[j]-pre1[j-i]*b1[i]%mod1+mod1)%mod1!=bs1 || (pre2[j]-pre2[j-i]*b2[i]%mod2+mod2)%mod2!=bs2) goto ac; ans+=i*(n/i-1);break; ac:; } printf("%lld ",ans); } return 0; }
T2
- 65的大众分只得了15分。
- 我的概率是真的垃圾。
- 题解的思路稍不懂,打的迪哥的思路。
- 求出每个点的先手胜率和从s开始用奇/偶数步到达每个点的概率。
- 最大胜率是将自己引到胜率最大的点或将对手引到胜率最小的点得到的结果。
- 平均胜率综合考虑所有情况即可。
- 时空复杂度$Theta(N)$。
#include<cstdio> #define ll long long using namespace std; int const N=1e5+5,M=3e5+5; int n,m,s; int head[N],Next[M],to[M],t; int rhc[N],du[N],rnxt[M],rto[M],rt; double win[N],al[N][2],tot,maxw,minw=2e9; double mx,av,ansx,ansv; inline int read(){ int ss(0),pp(1);char bb(getchar()); for(;bb<48||bb>57;bb=getchar())if(bb=='-')pp=-1; while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar(); return ss*pp; } inline void ad2(int x,int y){ ++du[rto[++rt]=y]; rnxt[rt]=rhc[x],rhc[x]=rt; return ; } inline void add(int x,int y){ to[++t]=y; Next[t]=head[x],head[x]=t; return ad2(y,x); } inline double max(double x,double y){ return x>y?x:y; } inline double min(double x,double y){ return x<y?x:y; } int main(){ //freopen("1.in","r",stdin); //freopen("1.out","w",stdout); n=read(),m=read(),al[s=read()][0]=1; for(register int i=1,ff,tt;i<=m;++i) ff=read(),tt=read(),add(ff,tt); scanf("%lf%lf",&mx,&av); for(register int i=n;i;--i){ tot+=win[i]; maxw=max(maxw,win[i]),minw=min(minw,win[i]); const double x=1.0-win[i]; for(register int j=rhc[i];j;j=rnxt[j]) win[rto[j]]+=x/(double)du[rto[j]]; } for(register int i=1;i<=n;++i){ const double on=al[i][0]/(double)du[i],jn=al[i][1]/(double)du[i]; for(register int j=head[i];j;j=Next[j]) al[to[j]][0]+=jn,al[to[j]][1]+=on; } double const swin=win[s]; for(register int i=1;i<=n;++i){ const double now=1.0/(double)(du[i]+1),nw=now*du[i], mxg=al[i][0]<al[i][1]?maxw:minw; ansx=max(ansx, swin-al[i][0]*win[i]-al[i][1]*(1-win[i]) +al[i][0]*now*(1-mxg)+al[i][1]*now*mxg +al[i][0]*nw*win[i]+al[i][1]*nw*(1-win[i])); } for(register int i=1;i<=n;++i){ double now=1.0/(double)(du[i]+1),z=(tot-win[i])/(double)(n-1); ansv+=(1-(al[i][0]+al[i][1])*now)*swin+al[i][0]*now*(1-z)+al[i][1]*now*z; } printf("%.3lf %.3lf ",ansx,ansv/(double)n); return 0; }
T3
- 考试想到了维护子树最大次大次次大的贡献,这样就可以做了。
- 不过觉得稍毒瘤于是最后才去打,没打完……
- 原本想用树链剖分,但题解给出了更优越的树上倍增。
- 想到这些本题就不难解决了。
- 时空复杂度$Theta(NlogN)$。
#include<cstdio> #include<cstring> #include<iostream> #define ll long long #define mp make_pair using namespace std; int const N=2e5+5,M=4e5+5; int n,m,ans; int head[N],Next[M],to[M],t; int dep[N],Log[N],f[N][19],mx[N][19]; pair<int,int>son[N][3]; int par[N]; inline int read(){ int ss(0);char bb(getchar()); while(bb<48||bb>57)bb=getchar(); while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar(); return ss; } inline void add(int x,int y){ to[++t]=y; Next[t]=head[x],head[x]=t; return ; } inline int max(int x,int y){ return x>y?x:y; } int dfs(int x,int fa){ int firs,firw=0,sces,scew=0,thrs,thrw=0,dnow=dep[x]+1; for(int i=head[x],y,z;i;i=Next[i]) if((y=to[i])^fa){ dep[y]=dnow,f[y][0]=x; for(register int j=0;j<Log[dnow];++j) f[y][j+1]=f[f[y][j]][j]; z=dfs(y,x); if(z>firw){ thrs=sces,thrw=scew; sces=firs,scew=firw; firs=y,firw=z; } else if(z>scew){ thrs=sces,thrw=scew; sces=y,scew=z; } else if(z>thrw) thrs=y,thrw=z; } ans=max(ans,firw+scew); son[x][0]=mp(firs,firw),son[x][1]=mp(sces,scew),son[x][2]=mp(thrs,thrw); return firw+1; } void redfs(int x,int fa){ int anow=par[x]+1,gl=son[x][0].first, firw=son[x][0].second,secw=son[x][1].second; for(int i=head[x],y,dnow=dep[x]+1;i;i=Next[i]) if((y=to[i])^fa){ mx[y][0]=(y==gl?secw:firw); par[y]=max(anow,mx[y][0]+1); for(register int j=0;j<Log[dnow];++j) mx[y][j+1]=max(mx[y][j],mx[f[y][j]][j]); redfs(y,x); } return ; } inline void _swap(int &x,int &y){ int z=x; x=y,y=z; return ; } inline int lca(int x,int y){ if(dep[x]<dep[y])_swap(x,y); int zans=son[x][0].second; for(register int i=Log[dep[x]];~i;--i) if(dep[f[x][i]]>=dep[y])zans=max(zans,mx[x][i]),x=f[x][i]; if(x==y)return max(zans,par[x]); zans=max(zans,son[y][0].second); for(register int i=Log[dep[x]];~i;--i) if(f[x][i]^f[y][i]) zans=max(zans,max(mx[x][i],mx[y][i])), x=f[x][i],y=f[y][i]; int fa=f[x][0]; zans=max(zans,par[fa]); if(son[fa][0].first!=x && son[fa][0].first!=y)return max(zans,son[fa][0].second); if(son[fa][1].first!=x && son[fa][1].first!=y)return max(zans,son[fa][1].second); return max(zans,son[fa][2].second); } int main(){ //freopen("1.in","r",stdin); //freopen("1.out","w",stdout); n=read(); Log[0]=-1; for(register int i=1,ff,tt;i<n;++i) Log[i]=Log[i>>1]+1,ff=read(),tt=read(),add(ff,tt),add(tt,ff); Log[n]=Log[n>>1]+1,dep[1]=1; dfs(1,0),ans=ans+2>>1; redfs(1,0); m=read(); while(m--){ int x=read(),y=read(); if(x==y){printf("%d ",ans);continue;} printf("%d ",lca(x,y)); } return 0; }