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);
}
}