3.27 模拟赛
T1
题目大意:
一棵树有正边权,$Q$次询问,询问$x$与编号在$[l,r]$之间的点的最小距离
思路:
建立点分树,由于在每个分治重心内任意两个点的lca可以看做重心
我们可以预处理出一个点到他点分树上所有的祖先的距离,每个点最多处理$log$个距离
对每个重心维护动态开点线段树,把每个点暴力加入到它点分树上祖先的线段树
查询的时候暴力查询所有祖先的线段树即可
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #define ll long long 12 #define db double 13 #define inf 21390621430000000LL 14 #define MAXN 100100 15 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i) 16 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i) 17 #define ren for(register int i=fst[x];i;i=nxt[i]) 18 #define pb(i,x) vec[i].push_back(x) 19 #define pls(a,b) (a+b)%MOD 20 #define mns(a,b) (a-b+MOD)%MOD 21 #define mul(a,b) (1LL*(a)*(b))%MOD 22 using namespace std; 23 inline int read() 24 { 25 int x=0,f=1;char ch=getchar(); 26 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 27 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 28 return x*f; 29 } 30 int n,nxt[MAXN<<1],fst[MAXN],to[MAXN<<1],cnt,val[MAXN<<1]; 31 int sz[MAXN],mx[MAXN],Mx,Sum,Rt,vis[MAXN],dep[MAXN],fa[MAXN]; 32 ll dis[MAXN][20]; 33 void add(int u,int v,int w) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;} 34 void getrt(int x,int pa) 35 { 36 sz[x]=1,mx[x]=0;ren if(to[i]^pa&&!vis[to[i]]) 37 {getrt(to[i],x);sz[x]+=sz[to[i]];mx[x]=max(mx[x],sz[to[i]]);} 38 mx[x]=max(mx[x],Sum-sz[x]);if(mx[x]<Mx) Mx=mx[x],Rt=x; 39 } 40 void Get(int x,int pa,int d){ren if(!vis[to[i]]&&to[i]^pa) dis[to[i]][d]=dis[x][d]+val[i],Get(to[i],x,d);} 41 void div(int x) 42 { 43 vis[x]=1;dis[x][dep[x]]=0;Get(x,0,dep[x]); 44 ren if(!vis[to[i]]) 45 {Sum=sz[to[i]],Mx=n+2;getrt(to[i],0);dep[Rt]=dep[x]+1,fa[Rt]=x;div(Rt);} 46 } 47 ll mn[MAXN<<7];int ls[MAXN<<7],rs[MAXN<<7],rt[MAXN],tot; 48 void mdf(int &k,int l,int r,int x,ll w) 49 { 50 if(!k) k=++tot,mn[k]=inf;mn[k]=min(mn[k],w);if(l==r) return ;int mid=l+r>>1; 51 if(x<=mid) mdf(ls[k],l,mid,x,w);else mdf(rs[k],mid+1,r,x,w); 52 } 53 ll query(int k,int l,int r,int a,int b) 54 { 55 if(!k) return inf;if(l==a&&r==b) return mn[k];int mid=l+r>>1; 56 if(b<=mid) return query(ls[k],l,mid,a,b); 57 else if(a>mid) return query(rs[k],mid+1,r,a,b); 58 else return min(query(ls[k],l,mid,a,mid),query(rs[k],mid+1,r,mid+1,b)); 59 } 60 void Mdf(int x){for(int anc=x;dep[anc];anc=fa[anc]) mdf(rt[anc],1,n,x,dis[x][dep[anc]]);} 61 ll Query(int x,int l,int r,ll res=inf) 62 { 63 for(int anc=x;dep[anc];anc=fa[anc]){res=min(res,dis[x][dep[anc]]+query(rt[anc],1,n,l,r));} 64 return res; 65 } 66 int main() 67 { 68 n=read();int a,b,c;rep(i,2,n) a=read(),b=read(),c=read(),add(a,b,c),add(b,a,c); 69 Mx=n+2,Sum=n;getrt(1,0);dep[Rt]=1;div(Rt);rep(i,1,n) Mdf(i); 70 int T=read();while(T--) {a=read(),b=read(),c=read();printf("%lld\n",Query(c,a,b));} 71 }
T2
题目大意:
把$n$个本质不同的东西分给$m$个本质相同的人,定义每种方案的权值为所有人拿到东西的数目成绩
求所有方案的权值和
思路:
对于每个方案的权值,可以看做给方案中对每个人都选一朵花的方案数
则我们可以先枚举出选出的这$m$朵花,即$C_n^m$ 剩下的花随便放即$m^{n-m}$,总方案数为贡献
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #define ll long long 12 #define db double 13 #define inf 2139062143 14 #define MAXN 100100 15 #define MOD 998244353 16 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i) 17 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i) 18 #define ren for(register int i=fst[x];i;i=nxt[i]) 19 #define pb(i,x) vec[i].push_back(x) 20 #define pls(a,b) (a+b)%MOD 21 #define mns(a,b) (a-b+MOD)%MOD 22 #define mul(a,b) (1LL*(a)*(b))%MOD 23 using namespace std; 24 inline int read() 25 { 26 int x=0,f=1;char ch=getchar(); 27 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 28 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 29 return x*f; 30 } 31 int n,m,pw[MAXN],ipw[MAXN]; 32 int q_pow(int bas,int t,int res=1) 33 { 34 for(;t;t>>=1,bas=mul(bas,bas)) 35 if(t&1) res=mul(res,bas);return res; 36 } 37 int C(int n,int m) {return mul(pw[n],mul(ipw[m],ipw[n-m]));} 38 int main() 39 { 40 n=read(),m=read();pw[0]=1;rep(i,1,n) pw[i]=mul(pw[i-1],i),ipw[i]=q_pow(pw[i],MOD-2); 41 printf("%d\n",mul(C(n,m),q_pow(m,n-m))); 42 }
T3
题目大意:
求树上选出$m$个点的点独立集的所有方案的权值和,一个方案的权值定义为选出的点的权值的乘积
思路:
设$f_{x,0/1}$表示选不选$x$这个点的答案
考虑合并一个新的子树进来合并,$f_{i+j,0}=t_{i,0}*f{j,0}$ 是一个卷积的形式
则我们可以用$ntt$来合并,但显然复杂度是不满足的
考虑重链剖分,先把重链上每个点的其他儿子的贡献算出来,得到一个$g_{x,0/1}$数组
为了快速合并重链上的信息,我们还需要记录选头不选尾,选尾不选头的情况。这样就可以用分治来优化了
这样一路合并上去就可以得到答案了
(指针可真是个弟弟,谜之分配内存
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<map> 10 #define ll long long 11 #define db double 12 #define inf 2139092143 13 #define MAXN 160100 14 #define MOD 998244353 15 #define rep(i,s,t) for(register int i=(s),i##end=(t);i<=i##end;++i) 16 #define dwn(i,s,t) for(register int i=(s),i##end=(t);i>=i##end;--i) 17 #define ren(x) for(int i=fst[x];i;i=nxt[i]) 18 #define pls(a,b) (a%MOD+b%MOD)%MOD 19 #define mns(a,b) ((a%MOD-b%MOD)%MOD+MOD)%MOD 20 #define mul(a,b) (1LL*(a%MOD)*(b%MOD))%MOD 21 #define inv(x) q_pow(x,MOD-2) 22 using namespace std; 23 inline int read() 24 { 25 int x=0,f=1;char ch=getchar(); 26 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 27 while(isdigit(ch)) {x=x*10+ch-'0',ch=getchar();} 28 return x*f; 29 } 30 int w[MAXN],n,m,nxt[MAXN<<1],fst[MAXN],to[MAXN<<1],cnt; 31 int sz[MAXN],hsh[MAXN],hvs[MAXN],fa[MAXN],tot,t[MAXN],tt[MAXN]; 32 void add(int u,int v) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v;} 33 int A[MAXN<<2],B[MAXN<<2],pw[30],ipw[30],rev[MAXN<<2],l2[MAXN<<2],tmp[MAXN<<8],*id=tmp; 34 int q_pow(int bas,int t,int res=1) 35 { 36 for(;t;t>>=1,bas=mul(bas,bas)) 37 if(t&1) res=mul(res,bas);return res; 38 } 39 void ntt(int *a,int n,int f) 40 { 41 rep(i,0,n-1) if(i<rev[i]) swap(a[i],a[rev[i]]); 42 for(int i=1;i<n;i<<=1) 43 { 44 int wn=f>0?pw[l2[i]+1]:ipw[l2[i]+1]; 45 for(int j=0;j<n;j+=i<<1) 46 { 47 int w=1,x,y; 48 for(int k=0;k<i;++k,w=mul(w,wn)) 49 x=a[j+k],y=mul(a[j+k+i],w),a[j+k]=pls(x,y),a[j+k+i]=mns(x,y); 50 } 51 } 52 if(f>0) return ;int nv=inv(n);rep(i,0,n-1) a[i]=mul(a[i],nv); 53 } 54 struct poly 55 { 56 int *a,len;void mem(int x) {len=x,a=id,id+=len;} 57 poly operator * (const poly &b) const 58 { 59 poly res;res.mem(len+b.len-1);int t=l2[res.len]+1,lmt=1<<t; 60 if(res.len<=100) 61 { 62 rep(i,0,len-1) rep(j,0,b.len-1) if(i+j<res.len) 63 res.a[i+j]=pls(mul(a[i],b.a[j]),res.a[i+j]);return res; 64 } 65 rep(i,0,lmt-1) rev[i]=(rev[i>>1]>>1)|((i&1)<<t-1),A[i]=B[i]=0; 66 rep(i,0,len-1) A[i]=a[i];rep(i,0,b.len-1) B[i]=b.a[i]; 67 ntt(A,lmt,1);ntt(B,lmt,1); 68 rep(i,0,lmt-1) A[i]=mul(A[i],B[i]);ntt(A,lmt,-1); 69 rep(i,0,res.len-1) res.a[i]=A[i];return res; 70 } 71 poly operator + (const poly &b) const 72 { 73 poly res;res.mem(max(len,b.len)); 74 rep(i,0,res.len-1) res.a[i]=pls((i<len?a[i]:0),(i<b.len?b.a[i]:0));return res; 75 } 76 }f[MAXN][2],g[MAXN][2],One,Zero; 77 poly solve(int l,int r,int D) 78 { 79 if(l==r) return f[t[l]][D];int mid=l+r>>1; 80 return solve(l,mid,D)*solve(mid+1,r,D); 81 } 82 struct mat{poly a[2][2];void mem() {a[0][0]=a[0][1]=a[1][1]=a[1][0]=Zero;}}; 83 mat merge(const mat &x,const mat &y) 84 { 85 mat res;res.a[1][1]=x.a[1][0]*(y.a[0][1]+y.a[1][1])+x.a[1][1]*y.a[0][1]; 86 res.a[1][0]=x.a[1][0]*(y.a[0][0]+y.a[1][0])+x.a[1][1]*y.a[0][0]; 87 res.a[0][1]=x.a[0][0]*(y.a[0][1]+y.a[1][1])+x.a[0][1]*y.a[0][1]; 88 res.a[0][0]=x.a[0][0]*(y.a[0][0]+y.a[1][0])+x.a[0][1]*y.a[0][0];return res; 89 } 90 mat solve(int l,int r) 91 { 92 if(l==r) {mat res;res.mem();res.a[0][0]=g[tt[l]][0],res.a[1][1]=g[tt[l]][1];return res;} 93 int mid=l+r>>1;return merge(solve(l,mid),solve(mid+1,r)); 94 } 95 void dfs(int x,int pa) 96 { 97 fa[x]=pa,hsh[++tot]=x,sz[x]=1; 98 ren(x) if(to[i]^pa) dfs(to[i],x),sz[x]+=sz[to[i]],hvs[x]=sz[to[i]]>sz[hvs[x]]?to[i]:hvs[x]; 99 } 100 void work(int x) 101 { 102 int l1=0,l2;poly it;mat res; 103 for(int y=x;y;y=hvs[y]) 104 { 105 tt[++l1]=y,l2=0;ren(y) if(to[i]^fa[y]&&to[i]^hvs[y]) t[++l2]=to[i]; 106 it.mem(2);it.a[0]=0;it.a[1]=w[y];if(!l2) g[y][0]=One,g[y][1]=it; 107 else g[y][0]=solve(1,l2,1),g[y][1]=solve(1,l2,0)*it; 108 } 109 res=solve(1,l1);f[x][0]=res.a[0][0]+res.a[0][1]; 110 f[x][1]=f[x][0]+res.a[1][0]+res.a[1][1]; 111 } 112 int main() 113 { 114 n=read(),m=read();int a,b;rep(i,1,n) w[i]=read();One.mem(1);One.a[0]=1; 115 rep(i,2,n) a=read(),b=read(),add(a,b),add(b,a);Zero.mem(1); 116 rep(i,2,n<<2) 117 { 118 l2[i]=l2[i>>1]+1; 119 if(!pw[l2[i]]) pw[l2[i]]=q_pow(3,(MOD-1)/i),ipw[l2[i]]=inv(pw[l2[i]]); 120 } 121 dfs(1,0);dwn(i,n,1) {a=hsh[i];if(hvs[fa[a]]^a) work(a);} 122 printf("%d\n",f[1][1].len>=m+1?f[1][1].a[m]:0); 123 }