【LOJ 2542】【PKUWC2018】 随机游走(最值反演 + 树上期望dp)
哇我太菜啦555555
不妨钦定我们需要访问的点集为S,在S已知的情况下,我们令f(x)表示从x走到点集S中任意一点的期望步数。
若x∈S,则显然f(x)=0,否则f[x]=1d[x]∑f[ch[x]]+1。其中d[x]表示与x相连的节点个数,ch[x]为与x相连的节点。
然后就列出了n条式子,显然是一个n元一次方程,可以考虑用高斯消元去求解,这样时间复杂度是O(n32n),只能拿60分(然而我考场上是零分啊呜呜呜)
我们考虑用些快速点的方法,考虑将f[x]化为Axf[fa[x]]+Bx。其中fa[x]表示x的父亲。则
f[x]=Ax[fa[x]]+Bx=1d[x]∑f[ch[x]]
f[x]=1d[x]f[fa[x]]+1d[x](Ach[x]f[x]+Bch[x])+1。
经过化简后,得
f[x]=f[fa[x]]+∑Bch[x]+1d[u]−∑Ach[x]
我们令g[S]表示从给定起点X出发,走到集合S中任意一个点的期望步数。
那么显然,g[S]=f[X]。求出所有状态的期望的时间复杂度显然为O(n2n)。
我们令G[S]表示从给定起点X出发,将集合S中每个点至少走一次的期望步数。
根据min−max容斥的相关内容,有
G[S]=∑i∈Sg[i]×(−1)|i|+1
然后我们可以花O(3n)枚举子集,预处理出所有答案。
查询的时候O(1)查询即可。
完结撒花
1 #include<bits/stdc++.h> 2 #define M 18 3 #define MOD 998244353 4 #define L long long 5 using namespace std; 6 7 L pow_mod(L x,L k){ 8 L ans=1; 9 while(k){ 10 if(k&1) ans=ans*x%MOD; 11 x=x*x%MOD; k>>=1; 12 } 13 return ans; 14 } 15 16 L d[M]={0},invd[M]={0}; 17 struct edge{int u,next;}e[M<<1]={0}; int head[M]={0},use=0; 18 void add(int x,int y){use++;e[use].u=y;e[use].next=head[x];head[x]=use;} 19 20 L f[1<<M]={0},ans[1<<M]={0},zf[1<<M]={0},a[M]={0},b[M]={0}; int ok[1<<M]={0}; 21 22 int n,q,rt; 23 void dfs(int x,int fa,int S){ 24 if((1<<x)&S) return; 25 for(int i=head[x];i;i=e[i].next) 26 if(e[i].u!=fa){ 27 dfs(e[i].u,x,S); 28 b[x]+=b[e[i].u]; 29 a[x]+=a[e[i].u]; 30 } 31 b[x]%=MOD; a[x]%=MOD; 32 L inv=pow_mod((d[x]-a[x]+MOD)%MOD,MOD-2); 33 a[x]=inv; 34 b[x]=(b[x]*inv+inv*d[x])%MOD; 35 } 36 37 void solve(int x){ 38 ok[x]=1; 39 for(int i=x;i;i=x&(i-1)) 40 ans[x]+=zf[i]*f[i]; 41 ans[x]=(ans[x]%MOD+MOD)%MOD; 42 } 43 44 int main(){ 45 //freopen("a.out","w",stdout); 46 scanf("%d%d%d",&n,&q,&rt); rt--; 47 for(int i=1;i<n;i++){ 48 int x,y; scanf("%d%d",&x,&y); 49 x--; y--; add(x,y); add(y,x); 50 d[x]++; d[y]++; 51 } 52 for(int i=0;i<n;i++) invd[i]=pow_mod(d[i],MOD-2); 53 int hh=1<<n; 54 for(int i=1;i<hh;i++){ 55 memset(a,0,sizeof(a)); 56 memset(b,0,sizeof(b)); 57 dfs(rt,-1,i); 58 f[i]=b[rt]; zf[i]=-1; 59 for(int j=0;j<n;j++) 60 if((1<<j)&i) zf[i]=-zf[i]; 61 } 62 while(q--){ 63 int k,hh=0; scanf("%d",&k); 64 while(k--){ 65 int x; scanf("%d",&x); 66 hh+=1<<(x-1); 67 } 68 if(!ok[hh]) solve(hh); 69 printf("%lld\n",ans[hh]); 70 } 71 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!