Noip模拟52 2021.9.13
T1 异或
比较稳的切掉
观察数据范围,无法线性筛啥的,根号复杂度也会死,于是只能考虑$log$级
然后打表
发现当$n$为$2^i$时的答案是一个可递归数列:
$1,3,7,15,31,63,127...$
这样的话直接把$n$进行二进制拆分,然后累加$2^i$的答案就可以出来最终答案
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 namespace AE86{ 5 inline int read(){ 6 int x=0,f=1;char ch=getchar(); 7 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 8 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f; 9 }inline void write(int x,char opt='\n'){ 10 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-'); 11 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x); 12 for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);} 13 }using namespace AE86; 14 15 const int NN=1e6+5,inf=0x3fffffff; 16 int n,er[65],cnt,pw,i,ans; 17 18 inline int getnum(int x){ 19 if(x==1) return 1; 20 return getnum(x/2)*2+1; 21 } 22 23 namespace WSN{ 24 inline short main(){ 25 n=read(); 26 while(n>0){ 27 pw=1,i=0;while(pw<=n) pw<<=1,++i; 28 --i; pw>>=1; n-=pw; er[++cnt]=pw; 29 } 30 for(i=1;i<=cnt;i++) ans+=getnum(er[i]); 31 write(ans); 32 return 0; 33 } 34 } 35 signed main(){return WSN::main();}
T2 赌怪
一道神仙$dp$题成功被乱搞为贪心。
按照题意模拟过程,每次找到最多的颜色种类然后按比例累乘答案即可
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 namespace AE86{ 5 inline int read(){ 6 int x=0,f=1;char ch=getchar(); 7 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 8 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f; 9 }inline void write(int x,char opt='\n'){ 10 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-'); 11 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x); 12 for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);} 13 }using namespace AE86; 14 15 const int NN=1e6+5,inf=0x3fffffff,mod=998244353; 16 inline int qmo(int a){ 17 int ans=1,c=mod,b=c-2; a%=c; 18 while(b){ 19 if(b&1) ans=ans*a%c; 20 b>>=1; a=a*a%c; 21 } return ans; 22 } 23 24 int n,a[NN],tot,ans=1,x; 25 priority_queue<int> q; 26 27 namespace WSN{ 28 inline short main(){ 29 n=read(); 30 for(int i=1,a;i<=n;i++){ 31 a=read(); tot+=a; 32 q.push(a); 33 } 34 while(!q.empty() && q.top() && tot){ 35 x=q.top(); q.pop(); 36 (ans*=n*x*qmo(tot)%mod)%=mod; --tot; 37 q.push(x-1); 38 } 39 write(ans); 40 return 0; 41 } 42 } 43 signed main(){return WSN::main();}
考场上还是要敢猜测答案,要不然会错失好机会
高能预警:T3T4暴力分数极高,无法想像暴力打满有200分
T3 路径
不少人点分治$n^2logn$能切(只因为我考场上打的点分治无法契合测试点(究级离谱)???)???
还有不少人使用$FFT$能切,(只有战神切的用正解:“您知道这是$OJ$上的原题吗?”)
确实是斯特林数的原题,也确实只有战神切掉了那道原题。。。。。
$x^i=\sum _{j=0}^{i}\begin{Bmatrix}k\\i \end{Bmatrix}*x^{\underline i}$
斯特林数小于100可以预处理。剩下的就需要求出$\sum_{u=0}^{k}\sum_{x=1}^{n-1}\sum_{y=x+1}^{n}dist(x,y)^{\underline u}$
考虑$dp$,设$f[i][j]=\sum_{u \in sub(i)}dis(fa[i],u)^{\underline j}$这个东西可以$dfs$预处理:
定义一个转移数组$g[i][j]=\sum_{son}f[son][j]=\sum_{son}(dis(i,u)-1)^{\underline j}$
发现用这个转移到$f[i][j]$可以用下降幂公式:$(x+1)^{\underline i}=i*x^{\underline {i-1}}+x^{\underline i}$
那么$f[i][j]=g[i][j-1]*j+g[i][j]$
然后考虑换根$dp$,
太丑,不过能看
从$fa$转移到$i$,考虑几件事情
1.现在的$g[fa][j]-f[i][j]$,算出$fa$剩下子树的贡献和
2.这个贡献算出新的$f[fa][j]$用下降幂公式,表示$fa$成为了$i$的子树后,对$i$作出的贡献
3.累加新的根的答案,新的$g[i][j]$为累加上那个$fa$的转移值
然后答案$ans_i=\sum_{u}g[u][i]$
最后答案=$\sum_{i}S[k][i]*ans[i]$
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int NN=1e6+5,inf=0x3fffffff,mod=998244353,v2=499122177; 4 namespace AE86{ 5 inline int read(){ 6 int x=0,f=1;char ch=getchar(); 7 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 8 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f; 9 }inline void write(int x,char opt='\n'){ 10 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-'); 11 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x); 12 for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);} 13 inline int max(int a,int b){return a>b?a:b;} 14 inline int min(int a,int b){return a<b?a:b;} 15 inline int mo(int x){return x>=mod?x-mod:x;} 16 }using namespace AE86; 17 18 struct SNOW{int to,next;}e[NN<<1]; int head[NN],rp; 19 inline void add(int x,int y){ 20 e[++rp]=(SNOW){y,head[x]};head[x]=rp; 21 e[++rp]=(SNOW){x,head[y]};head[y]=rp; 22 } 23 24 int n,k,S[105][105],f[NN][101],g[NN][101],ans[105],tmp[105],answer; 25 26 inline void dfs(int fa,int x){ 27 int maxn=0; 28 for(int i=head[x];i;i=e[i].next) if(fa!=e[i].to){ 29 dfs(x,e[i].to); 30 for(int j=0;j<=k;j++){ 31 if(!f[e[i].to][j]) break; maxn=max(maxn,j); 32 g[x][j]=mo(g[x][j]+f[e[i].to][j]); 33 } 34 } 35 ++g[x][0]; f[x][0]=g[x][0]; 36 for(int i=min(k,maxn+1);i;--i) 37 f[x][i]=mo(1ll*i*g[x][i-1]%mod+g[x][i]); 38 } 39 40 inline void get(int fa,int x){ 41 int maxn=0; 42 for(int i=0;i<=k;i++){ 43 if(!g[x][i]) break;maxn=i; 44 ans[i]=mo(ans[i]+g[x][i]); 45 } maxn=min(k,maxn+1); 46 for(int i=head[x];i;i=e[i].next) if(fa!=e[i].to){ 47 for(int j=0;j<=maxn;j++) tmp[j]=mo(g[x][j]-f[e[i].to][j]+mod); 48 for(int j=maxn;j;j--) tmp[j]=mo(tmp[j]+1ll*tmp[j-1]*j%mod); 49 for(int j=0;j<=maxn;j++) g[e[i].to][j]=mo(tmp[j]+g[e[i].to][j]); 50 get(x,e[i].to); 51 } 52 } 53 54 namespace WSN{ 55 inline short main(){ 56 // freopen("in.in","r",stdin); 57 // freopen("std.out","w",stdout); 58 n=read(); k=read(); S[0][0]=1; 59 for(int i=1;i<=k;i++) for(int j=1;j<=i;j++) 60 S[i][j]=mo(S[i-1][j-1]+1ll*S[i-1][j]*j%mod); 61 for(int i=1,u,v;i<n;i++) u=read(),v=read(),add(u,v); 62 dfs(0,1); get(0,1); 63 for(int i=0;i<=k;i++) answer=mo(answer+1ll*S[k][i]*ans[i]%mod); 64 answer=1ll*answer*v2%mod; 65 write(answer); 66 return 0; 67 } 68 } 69 signed main(){return WSN::main();}
T4 树
考场上都用暴力水过了,可是我没太管这道题,可恶。。。
1 #include<bits/stdc++.h> 2 using namespace std; 3 namespace AE86{ 4 inline int read(){ 5 int x=0,f=1;char ch=getchar(); 6 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 7 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f; 8 }inline void write(int x,char opt='\n'){ 9 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-'); 10 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x); 11 for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);} 12 }using namespace AE86; 13 14 const int NN=3e5+1; 15 struct SNOW{int to,next;}e[NN<<1]; int head[NN],rp; 16 inline void add(int x,int y){ 17 e[++rp]=(SNOW){y,head[x]};head[x]=rp; 18 e[++rp]=(SNOW){x,head[y]};head[y]=rp; 19 } 20 int n,q,rt[NN],dfn[NN],cnt,dep[NN],siz[NN],ans,maxdep; 21 inline void dfs(int f,int x){ 22 dfn[x]=++cnt; dep[x]=dep[f]+1; siz[x]=1; maxdep=max(maxdep,dep[x]); 23 for(int i=head[x];i;i=e[i].next) if(f!=e[i].to) 24 dfs(x,e[i].to),siz[x]+=siz[e[i].to]; 25 } 26 27 struct SNOWtree{ 28 int ls[NN*40],rs[NN*40],seg,sum[NN*40]; 29 inline void insert(int &x,int l,int r,int L,int R,int val){ 30 if(!x) x=++seg; 31 if(L<=l&&r<=R){sum[x]+=val;return;} 32 int mid=(l+r)>>1; 33 if(l<=mid) insert(ls[x],l,mid,L,R,val); 34 if(r>mid) insert(rs[x],mid+1,r,L,R,val); 35 } 36 inline int query(int x,int l,int r,int pos){ 37 ans+=sum[x]; if(l==r) return ans; 38 int mid=(l+r)>>1; 39 if(pos<=mid) return query(ls[x],l,mid,pos); 40 else return query(rs[x],mid+1,r,pos); 41 } 42 }tr; 43 44 namespace WSN{ 45 inline short main(){ 46 n=read(); q=read(); 47 for(int i=1,u,v;i<n;i++){ 48 u=read(),v=read(); 49 add(u,v); 50 } dfs(0,1); 51 int opt,v,x,z,y,res; 52 while(q--){ 53 opt=read(),v=read(); 54 if(opt==1){ 55 x=read(),y=read(),z=read(); res=y+dep[v]; 56 for(res=y+dep[v];res<=maxdep;res+=x) 57 tr.insert(rt[res],1,n,dfn[v],dfn[v]+siz[v]-1,z); 58 } 59 if(opt==2){ans=0;write(tr.query(rt[dep[v]],1,n,dfn[v]));} 60 } 61 return 0; 62 } 63 } 64 signed main(){return WSN::main();}
然而暴力被卡掉了,在晚上,所以姑姑沽