总参赛人数:15
有点菜。
不知道是撞了什么大运没有滚出A层。
但是一回到A层就暴露出了一个大问题:码速。
不是调试速度,,就是纯粹码的速度。。。
边讲考试状态边说吧。。。
上来肝T1。一看,是个换根的题?没做过啊。。。
LCT?啊?还要维护子树???这不是之前看的top_tree吗?
600行的玩意考场上还是不要考虑的。
然后就走上了一条不归路。
一个真正坑的暴力就是暴力的码量和调试难度都比正解还高。
幸而都是打熟了的东西,板子出锅倒不多。
但是纯粹码出来用了一个小时???感觉状态也不是很好。
然后没有过大样例,调了一阵没找出来然后决定先看T2T3。
其实出锅的地方是我想尝试改一下板子的某一个地方还坚定地认为它是对的。
T3只要有一点二进制思想就会的特别蠢的dp打出来,尝试优化,明知道它是个多项式。
但因为不会母函数所以即使打了NTT也只会多13分,而时间不够了就没有打(两小时了三道题还都没有分)
随便扔了个暴力dp上去,赶紧回去调T1。
中途给T2打表尝试找规律,然后脸去上厕所,回来的时候看我还在打表发呆就笑话我。
我也不知道他在笑话什么,大概意思就是他T1切了T2也找到规律了吧。。与我无瓜。
最后回T1,怕爆零于是打了一个更暴力的(21分)然后与目标40分的对拍。
打暴力+对拍又码了好久(大半个小时?)。然后调出来倒挺快的。但是这时候只剩下21分钟了。
这时候估计就算想出来哪道题了也打不完了吧。。。于是把T2的表扔了上去,没开long long丢了16分。
期望40+13+46=99。实际86。
可以发现。我的最高期望得分还不如A掉一个然后剩下两个都爆零。
说白了这次考试过程看下来的确很忙但是有一个特点:
没时间思考。一直在码。
这就很不妙了,码到底不出锅还不如认认真真打一道题。。。
看全机房最胖的三个都把T1A了总分就是前三名。
OI主要考的不是码力,真正要区分的就是脑子!
其实我也不能说是不会。T1的代码框架也已经出来了,再想想肯定不会局限与40分。
因为正解并不鬼畜,虽然新颖一些,但是难度并不高。
要思考。
说是在的到底为什么没有思考呢?其实原因倒有很多:首先有点不适应A卷,然后对数据结构有些害怕,还有潜意识里貌似就把自己拍死在暴力上了。
说白了就一句:不要怂,动脑子!
某种意义上,没有思考的话,可能就是浪费了一套卷子。
和前面的考试有些不一样,有时候是想了太久没码,有时候是码了太久没想。
积累经验,自行权衡。
第一次回A卷就不说什么了,希望下一次能不要这么惨吧。。。
T1:Tree
换根是假的。
拍在dfs序上维护子树。
分类讨论要操作的点和当前的根的关系来判断要修改的dfs序区间。
没有那么难。

1 #include<cstdio> 2 int n,q,cnt,fir[300005],l[600005],to[600005],f[300005][20],tim,root=1; 3 long long W[300005];int re[300005],dfn[300005],rdfn[300005],dep[300005]; 4 struct Segment_Tree{ 5 int cl[12000005],cr[12000005];long long lz[12000005],w[12000005]; 6 void build(int p,int l,int r){ 7 cl[p]=l;cr[p]=r; 8 if(l==r){w[p]=W[re[l]];return;} 9 build(p<<1,l,l+r>>1); 10 build(p<<1|1,(l+r>>1)+1,r); 11 w[p]=w[p<<1]+w[p<<1|1]; 12 } 13 void down(int p){//printf("down:%d ",p); 14 lz[p<<1]+=lz[p];lz[p<<1|1]+=lz[p]; 15 w[p<<1]+=lz[p]*(cr[p<<1]-cl[p<<1]+1); 16 w[p<<1|1]+=lz[p]*(cr[p<<1|1]-cl[p<<1|1]+1); 17 lz[p]=0;w[p]=w[p<<1]+w[p<<1|1]; 18 } 19 void add(int p,int l,int r,long long W){//printf("%d %d %d %lld ",p,cl[p],cr[p],W); 20 if(l<=cl[p]&&cr[p]<=r){lz[p]+=W;w[p]+=W*(cr[p]-cl[p]+1);return;} 21 if(lz[p])down(p); 22 if(l<=cr[p<<1])add(p<<1,l,r,W); 23 if(r>=cl[p<<1|1])add(p<<1|1,l,r,W); 24 w[p]=w[p<<1]+w[p<<1|1]; 25 } 26 long long ask(int p,int l,int r){//printf("ask:%d %d %d %lld ",p,l,r,lz[p]); 27 if(l<=cl[p]&&cr[p]<=r)return w[p]; 28 if(lz[p])down(p); 29 return (l<=cr[p<<1]?ask(p<<1,l,r):0)+(r>=cl[p<<1|1]?ask(p<<1|1,l,r):0); 30 } 31 }tree; 32 void dfs(int p){ 33 dfn[p]=++tim;re[tim]=p;dep[p]=dep[f[p][0]]+1; 34 for(int i=1;i<=19;++i)f[p][i]=f[f[p][i-1]][i-1]; 35 for(int i=fir[p];i;i=l[i])if(to[i]!=f[p][0])f[to[i]][0]=p,dfs(to[i]); 36 rdfn[p]=tim; 37 } 38 long long read(register long long p=0,register char ch=getchar(),register int nt=1){ 39 while(ch<'0'||ch>'9'){if(ch=='-')nt=-1;ch=getchar();} 40 while(ch>='0'&&ch<='9')p=(p<<3)+(p<<1)+ch-'0',ch=getchar(); 41 return p*nt; 42 } 43 int lca(int x,int y){ 44 int subdep=dep[x]-dep[y]; 45 if(subdep<0)subdep*=-1,x^=y^=x^=y; 46 for(int i=19;~i;--i)if(subdep&1<<i)x=f[x][i]; 47 if(x==y)return x; 48 for(int i=19;~i;--i)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i]; 49 return f[x][0]; 50 } 51 int getson(int x,int ff){ 52 int subdep=dep[x]-dep[ff]-1; 53 for(int i=19;~i;--i)if(subdep&1<<i)x=f[x][i]; 54 return x; 55 } 56 void link(int a,int b){l[++cnt]=fir[a];fir[a]=cnt;to[cnt]=b;} 57 int main(){//freopen("tree2.in","r",stdin);freopen("my.out","w",stdout); 58 n=read();q=read(); 59 for(int i=1;i<=n;++i)W[i]=read(); 60 for(int i=1,a,b;i<n;++i)a=read(),b=read(),link(a,b),link(b,a); 61 dfs(1);tree.build(1,1,n); 62 for(int i=1,opt,u,v,a,b,c,S,LCA;i<=q;++i){ 63 opt=read();u=read();long long x; 64 if(opt==1)root=u; 65 if(opt==2){ 66 v=read();x=read(); 67 c=lca(u,v);a=lca(root,u);b=lca(root,v); 68 if(dep[a]>dep[b])LCA=a;else LCA=b; 69 if(dep[c]>dep[LCA])LCA=c; 70 if(LCA==root)tree.add(1,1,n,x); 71 else if(dfn[LCA]<=dfn[root]&&rdfn[root]<=rdfn[LCA])tree.add(1,1,n,x),S=getson(root,LCA),tree.add(1,dfn[S],rdfn[S],-x); 72 else tree.add(1,dfn[LCA],rdfn[LCA],x); 73 } 74 if(opt==3){ 75 if(root==u)printf("%lld ",tree.ask(1,1,n)); 76 else if(dfn[u]<=dfn[root]&&rdfn[root]<=rdfn[u])S=getson(root,u),printf("%lld ",tree.ask(1,1,n)-tree.ask(1,dfn[S],rdfn[S])); 77 else printf("%lld ",tree.ask(1,dfn[u],rdfn[u])); 78 } 79 } 80 }
思路积累:
- 不要把思路拘束于新学的东西上。
- 能换根的数据结构不多,但是换根不一定真的要重建树,而只是修改了父子关系而已。
- 问题的转化。研究性质。
T2:Function
神仙题。另写题解。
T3:Or
dp[i][j]为已经选了i个数,二进制下已经有了j个1。

1 #include<cstdio> 2 #define int long long 3 #define mod 998244353 4 int pw[30005],f[2][30005],n,k,fac[30004],invv[30005],inv[30005],ans; 5 int C(int b,int t){return fac[b]*inv[t]%mod*inv[b-t]%mod;} 6 main(){ 7 scanf("%lld%lld",&n,&k); 8 invv[1]=fac[1]=fac[0]=inv[0]=inv[1]=f[0][0]=pw[0]=1;pw[1]=2; 9 for(int i=2;i<=k;++i)fac[i]=fac[i-1]*i%mod,invv[i]=mod-mod/i*invv[mod%i]%mod,inv[i]=inv[i-1]*invv[i]%mod,pw[i]=(pw[i-1]<<1)%mod; 10 for(int i=1;i<=n;++i)for(int j=i;j<=k;++j){ 11 f[i&1][j]=0; 12 for(int t=i-1;t<j;++t)f[i&1][j]+=f[i&1^1][t]*C(k-t,j-t)%mod*pw[t]%mod; 13 f[i&1][j]%=mod;//printf("%lld %lld %lld ",i,j,f[i&1][j]); 14 } 15 for(int j=n;j<=k;++j)ans+=f[n&1][j]; 16 printf("%lld ",ans%mod); 17 }
转移的式子符合卷积形式,NTT做n遍可以多拿13分。

1 #include<cstdio> 2 #define int long long 3 #define mod 998244353 4 int pw[880005],f[880005],n,k,fac[880004],invv[880005],inv[880005],ans,rev[880005],Inv,invNTT[880005],bin=1; 5 int pow(int b,int t,int a=1){for(;t;t>>=1,b=b*b%mod)if(t&1)a=a*b%mod;return a;} 6 void NTT(int *a,int opt){ 7 for(int i=1;i<bin;++i)if(rev[i]<i)a[i]^=a[rev[i]]^=a[i]^=a[rev[i]]; 8 for(int mid=1;mid<bin;mid<<=1) 9 for(int i=0,w=pow(3,opt*(mod-1)/mid/2+mod-1);i<bin;i+=mid<<1) 10 for(int j=0,wn=1;j<mid;++j,wn=wn*w%mod){ 11 int x=a[i+j],y=a[i+j+mid]*wn%mod; 12 a[i+j]=(x+y)%mod;a[i+j+mid]=(x-y+mod)%mod; 13 } 14 if(opt==-1)for(int i=0;i<bin;++i)a[i]=a[i]*Inv%mod; 15 } 16 main(){ 17 scanf("%lld%lld",&n,&k); 18 invv[1]=fac[1]=fac[0]=inv[0]=inv[1]=f[0]=pw[0]=1;pw[1]=2; 19 while(bin<=k)bin<<=1; bin<<=1;Inv=pow(bin,mod-2); 20 for(int i=2;i<=k;++i)fac[i]=fac[i-1]*i%mod,invv[i]=mod-mod/i*invv[mod%i]%mod,inv[i]=inv[i-1]*invv[i]%mod,pw[i]=(pw[i-1]<<1)%mod; 21 for(int i=1;i<=k;++i)invNTT[i]=inv[i]; 22 for(int i=1;i<bin;++i)rev[i]=rev[i>>1]>>1|(i&1)*bin>>1; 23 NTT(invNTT,1); 24 for(int i=1;i<=n;++i){ 25 for(int s=0;s<bin;++s)f[s]=f[s]*pw[s]%mod*fac[k-s]%mod; 26 NTT(f,1); 27 for(int s=0;s<bin;++s)f[s]=f[s]*invNTT[s]%mod; 28 NTT(f,-1); 29 for(int s=0;s<bin;++s)f[s]=f[s]*inv[k-s]%mod; 30 } 31 for(int j=0;j<=k;++j)ans+=f[j]; 32 printf("%lld ",ans%mod); 33 }
NC写的题解看不懂,还要高阶求导做前置知识。
然后用母函数倍增瞎改一下就A了。(题解待补)

1 #include<cstdio> 2 #define int long long 3 #define mod 998244353 4 int pw[80005],f[80005],n,k,fac[80005],invv[80005],inv[80005],ans,rev[80005],Inv,bin=1,re[80005]; 5 int pow(int b,int t,int a=1){for(;t;t>>=1,b=b*b%mod)if(t&1)a=a*b%mod;return a;} 6 void NTT(int *a,int opt){ 7 for(int i=1;i<bin;++i)if(rev[i]<i)a[i]^=a[rev[i]]^=a[i]^=a[rev[i]]; 8 for(int mid=1;mid<bin;mid<<=1) 9 for(int i=0,w=pow(3,opt*(mod-1)/mid/2+mod-1);i<bin;i+=mid<<1) 10 for(int j=0,wn=1;j<mid;++j,wn=wn*w%mod){ 11 int x=a[i+j],y=a[i+j+mid]*wn%mod; 12 a[i+j]=(x+y)%mod;a[i+j+mid]=(x-y+mod)%mod; 13 } 14 if(opt==-1)for(int i=0;i<bin;++i)a[i]=a[i]*Inv%mod; 15 } 16 void mul(){ 17 NTT(f,1);NTT(re,1); 18 for(int i=0;i<bin;++i)f[i]=f[i]*re[i]%mod,re[i]=0; 19 NTT(f,-1); 20 for(int i=k+1;i<bin;++i)f[i]=0; 21 } 22 void G(int N){ 23 if(N==1){for(int i=1;i<=k;++i)f[i]=inv[i];return;} 24 G(N>>1); 25 for(int res=1,i=1;i<=k;++i)re[i]=(res=res*pw[N>>1]%mod)*f[i]%mod; mul(); 26 if(N&1){for(int res=1,i=1;i<=k;++i)re[i]=(res=res*pw[N-1]%mod)*inv[i]%mod; mul();} 27 } 28 main(){ 29 scanf("%lld%lld",&n,&k); 30 invv[1]=fac[1]=fac[0]=inv[1]=pw[0]=inv[0]=1;pw[1]=2; 31 while(bin<=k)bin<<=1; bin<<=1;Inv=pow(bin,mod-2); 32 for(int i=2;i<=k;++i)fac[i]=fac[i-1]*i%mod,invv[i]=mod-mod/i*invv[mod%i]%mod,inv[i]=inv[i-1]*invv[i]%mod,pw[i]=(pw[i-1]<<1)%mod; 33 for(int i=1;i<bin;++i)rev[i]=rev[i>>1]>>1|(i&1)*bin>>1; 34 G(n); 35 for(int j=n;j<=k;++j)ans=(ans+f[j]*fac[k]%mod*inv[k-j])%mod; 36 printf("%lld ",ans); 37 }