T1
题目描述:
题目分析:
签到神仙题。
每条边的权值相当于是规定了子树内的点要被划分成 边权/2 段。
然后要把儿子的段以及自己合并成当前需要的段数,要保证在同一个儿子子树内的不能相邻。
于是容斥,钦定儿子子树的段至少有 段相邻,带上 的系数。
然后合并转移,复杂度 。
合并完之后再划分为当前需要的段数。
根节点确定在第一位,特殊处理,最后答案因为是环所以乘上
Code:
#include<bits/stdc++.h>
#define maxn 5005
using namespace std;
int n,mod,f[maxn],g[maxn],h[maxn],fac[maxn],inv[maxn],C[maxn][maxn];
int fir[maxn],nxt[maxn<<1],to[maxn<<1],w[maxn<<1],tot;
void line(int x,int y,int z){nxt[++tot]=fir[x],fir[x]=tot,to[tot]=y,w[tot]=z;}
void dfs(int u,int ff,int K){
for(int i=fir[u],v;i;i=nxt[i]) if((v=to[i])!=ff) dfs(v,u,w[i]);
g[1]=1; int S = 1;
for(int i=fir[u],v;i;i=nxt[i]) if((v=to[i])!=ff){
for(int j=1;j<=S+w[i];j++) h[j]=0;
for(int j=1;j<=S;j++)
for(int k=1;k<=w[i];k++)
h[j+k]=(h[j+k]+1ll*(w[i]-k&1?-1:1)*g[j]*f[v]%mod*C[w[i]-1][k-1]%mod*inv[k])%mod;
S+=w[i];
for(int j=1;j<=S;j++) g[j]=h[j];
}
if(u!=1) for(int i=K;i<=S;i++) f[u]=(f[u]+1ll*g[i]*fac[i]%mod*C[i-1][K-1])%mod;
else for(int i=1;i<=S;i++) f[1]=(f[1]+1ll*g[i]*fac[i-1])%mod;
}
int main()
{
freopen("permu.in","r",stdin);
freopen("permu.out","w",stdout);
scanf("%d%d",&n,&mod);
fac[0]=fac[1]=inv[0]=inv[1]=1;
for(int i=2;i<=n;i++) fac[i]=1ll*fac[i-1]*i%mod,inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
for(int i=2;i<=n;i++) inv[i]=1ll*inv[i-1]*inv[i]%mod;
for(int i=0;i<=n;i++)
for(int j=C[i][0]=1;j<=i;j++)
C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
for(int i=1,x,y,z;i<n;i++) scanf("%d%d%d",&x,&y,&z),z>>=1,line(x,y,z),line(y,x,z);
dfs(1,0,0);
printf("%d\n",(1ll*f[1]*n%mod+mod)%mod);
}
T2
题目描述:
题目分析:
咕咕咕
乘积很好算,不多说。
T3
题目描述:
题目分析:
一段 为 的串,它的运算结果可以写成一个 的矩阵,表示左边为 0/1 时算到右边为 0/1 的概率。
如果没有括号,可以用线段树维护这个矩阵。
括号实际上形成了一个树形结构,一棵子树表示一个括号,根记录这棵子树的运算结果为 0/1 的概率。
重链剖分,每个点用根据轻儿子维护出一个矩阵表示重儿子为 0/1 时子树结果为 0/1 的概率,重链用线段树维护。
看上去维护矩阵还需要对轻儿子建线段树,但是实际上我们可以把这棵树转成二叉树的形式。
(不把运算符看做点是可以做的,但是看做点会方便许多)
因为这个题的运算符都是二元运算符,所以可以把一个括号内的表达式表示成这种形式:
这样就形成了一个二叉树的结构,维护的东西仍然是重儿子为 0/1 时子树运算结果为 0/1 的概率。此时非叶节点都是运算符,叶节点为 0/1。
实际上不需要维护矩阵,只需要两个数,表示重儿子为 0 时结果为 0 的概率,以及重儿子为 1 时结果为 1 的概率。因为结果要么是 1 要么是 0,所以可以推出另外两个概率。
并且这样根节点维护的信息就是对应结果为 0/1 的概率。
然后就是动态DP模板了。
Code:
#include<bits/stdc++.h>
#define maxn 200005
using namespace std;
char cb[1<<20],*cs,*ct;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<20,stdin),cs==ct)?0:*cs++)
void read(int &a){
char c;while(!isdigit(c=getc()));
for(a=c-'0';isdigit(c=getc());a=a*10+c-'0');
}
const int mod = 998244353;
int n,m,ch[maxn][2],root,fa[maxn],siz[maxn],son[maxn],top[maxn],dfn[maxn],ln[maxn],bot[maxn],tim;
int Pow(int a,int b){int s=1;for(;b;b>>=1,a=1ll*a*a%mod) b&1&&(s=1ll*s*a%mod);return s;}
struct node{
int t,x,y,z;
void Div(){
int s=Pow(x+y+z,mod-2);
x=1ll*x*s%mod,y=1ll*y*s%mod,z=1ll*z*s%mod;
}
}A[maxn];
struct data{
int a,b;//son is 0, to be 0 possibility is a, son is 1, to be 1 possibility is b.
data operator + (const data &p)const{
return (data){(1ll*p.a*a+1ll*(1-p.a)*(1-b))%mod,(1ll*(1-p.b)*(1-a)+1ll*p.b*b)%mod};
}
}g[maxn],t[maxn<<2];
int rt[maxn],lc[maxn<<2],rc[maxn<<2],sz;
void init(int u,const data &p){
g[u].a=(A[u].x+1ll*(A[u].y+A[u].z)*p.a)%mod;
g[u].b=(1ll*A[u].x*p.b+1ll*A[u].y*(p.a+p.b)+1ll*A[u].z*p.a)%mod;
}
void build(int &i,int l,int r){
if(i=++sz,l==r) {t[i]=g[ln[l]];return;}
int mid=(l+r)>>1;
build(lc[i],l,mid),build(rc[i],mid+1,r);
t[i]=t[lc[i]]+t[rc[i]];
}
void dfs1(int u){
siz[u]=1; if(!ch[u][0]) return;
for(int i=0,v;i<2;i++) fa[v=ch[u][i]]=u,dfs1(v),siz[u]+=siz[v],siz[v]>siz[son[u]]&&(son[u]=v);
}
void dfs2(int u,int tp){
top[u]=tp,ln[dfn[u]=++tim]=u;
if(son[u]){
dfs2(son[u],tp); int v=ch[u][ch[u][0]==son[u]];
dfs2(v,v),init(u,t[rt[v]]);
}
else bot[tp]=tim,g[u]=(data){A[u].x,A[u].y};
if(u==tp) build(rt[u],dfn[u],bot[u]);
}
void ins(int i,int l,int r,int x){
if(l==r) {t[i]=g[ln[x]];return;}
int mid=(l+r)>>1;
x<=mid?ins(lc[i],l,mid,x):ins(rc[i],mid+1,r,x);
t[i]=t[lc[i]]+t[rc[i]];
}
void Modify(int u){
if(A[u].t==1) g[u]=(data){A[u].x,A[u].y};
else init(u,t[rt[ch[u][ch[u][0]==son[u]]]]);
int tp=top[u];
ins(rt[tp],dfn[tp],bot[tp],dfn[u]);
for(u=fa[tp];u;u=fa[tp])
init(u,t[rt[tp]]),tp=top[u],ins(rt[tp],dfn[tp],bot[tp],dfn[u]);
}
int S[maxn],L[maxn],tp,bt;
int Build(int l,int r){
if(l==r) return S[l];
ch[S[r-1]][1]=S[r],ch[S[r-1]][0]=Build(l,r-2);
return S[r-1];
}
int main()
{
freopen("structure.in","r",stdin);
freopen("structure.out","w",stdout);
read(n),read(m);
for(int i=1;i<=n;i++){
read(A[i].t);
if(A[i].t==1) read(A[i].x),read(A[i].y);
if(A[i].t==2) read(A[i].x),read(A[i].y),read(A[i].z);
if(A[i].t<=2) S[++tp]=i,A[i].Div();
if(A[i].t==3) L[++bt]=tp+1;
if(A[i].t==4) S[L[bt]]=Build(L[bt],tp),tp=L[bt--];
}
root=Build(1,tp);
dfs1(root),dfs2(root,root);
for(int i;m--;){
read(i);
read(A[i].x),read(A[i].y); if(A[i].t==2) read(A[i].z); A[i].Div();
Modify(i);
printf("%d\n",(t[rt[root]].b+mod)%mod);
}
}