LOJ2542. 「PKUWC2018」隨機遊走
阿新 • • 發佈:2019-01-01
LOJ2542. 「PKUWC2018」隨機遊走
分析:
- 為了學習最值反演而做的這道題~
-
- \(max{S}=\sum\limits_{T\subseteq S}(-1)^{|T|-1}min{T}\)
考慮排序後的\(a\)序列。
- \(max{S}=\sum\limits_{T\subseteq S}(-1)^{|T|-1}min{T}\)
- \(\sum\limits_{T\subseteq S}(-1)^{|T|-1}min{T}=\sum\limits_{i=1}^na_i\sum\limits_{j=0}^{n-i}(-1)^j\binom{n-i}{j}\)
- \(\sum\limits_{T\subseteq S}(-1)^{|T|-1}min{T}=\sum\limits_{i=1}^na_i[n-i=0]\)
- \(\sum\limits_{T\subseteq S}(-1)^{|T|-1}min{T}=a_n=max{S}\)
- 設\(f_{s,i}\)表示\(f\)第一次走到\(s\)狀態的期望步數。
- 這個東西我們直接列舉\(s\)然後樹上高斯消元即可。
- 最後再\(fwt\)一下就能得到反演後的\(min_s\)了。
程式碼:
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <cmath> using namespace std; #define mod 998244353 typedef long long ll; #define N 20 #define M ((1<<18)+50) int n,head[N],to[N<<1],nxt[N<<1],du[N],rt,m; int S,Cnt[M],cnt; inline void add(int u,int v) {to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;} ll K[N],B[N],inv[N],f[M]; ll qp(ll x,ll y) { ll re=1; for(;y;y>>=1,x=x*x%mod)if(y&1)re=re*x%mod;return re; } void dfs(int x,int y) { int i; if(S&(1<<(x-1))) {K[x]=B[x]=0; return ;} K[x]=inv[du[x]]; B[x]=1; ll lhs=1; for(i=head[x];i;i=nxt[i]) if(to[i]!=y) { dfs(to[i],x); lhs=(lhs-K[to[i]]*inv[du[x]])%mod; B[x]=(B[x]+B[to[i]]*inv[du[x]])%mod; } lhs=qp(lhs,mod-2); K[x]=K[x]*lhs%mod; B[x]=B[x]*lhs%mod; } void fwt(ll *a,int len) { int i,j,k,t; for(k=2;k<=len;k<<=1) for(t=k>>1,i=0;i<len;i+=k) for(j=i;j<i+t;j++) a[j+t]=(a[j+t]+a[j])%mod; } int main() { scanf("%d%d%d",&n,&m,&rt); int i,x,y; for(i=1;i<n;i++) { scanf("%d%d",&x,&y); add(x,y); add(y,x); du[x]++; du[y]++; } for(i=1;i<=n;i++) inv[i]=qp(i,mod-2); int mask=(1<<n)-1; for(i=0;i<=mask;i++) { S=i; dfs(rt,0); Cnt[i]=Cnt[i>>1]+(i&1); f[i]=B[rt]; if(!(Cnt[i]&1)) f[i]=-f[i]; } fwt(f,(1<<n)); while(m--) { int k,s=0; scanf("%d",&k); while(k--) { scanf("%d",&x); s|=(1<<(x-1)); } printf("%lld\n",(f[s]+mod)%mod); } }