zoukankan      html  css  js  c++  java
  • loj 2542 随机游走 —— 最值反演+树上期望DP+fmt

    题目:https://loj.ac/problem/2542

    因为走到所有点的期望就是所有点期望的最大值,所以先最值反演一下,问题变成从根走到一个点集任意一点就停止的期望值;

    设 ( f[x] ),则 ( f[x] = frac{f[fa]+1+sumlimits_{v in son} (f[v]+1)}{d[x]} ),其中 ( d[x] ) 是 ( x ) 的度数;

    因为其实只和 ( fa ) 有关,所以套路是设 ( f[x] = K[x] * f[fa] + B[x] ),推一推就可以树形DP求 ( K[x] , B[x] ),这好像叫“树上高斯消元”?!

    因为走到集合内任意一个点就停止,所以 ( K[x] = B[x] = 0 ( x in S ) ),( f[rt] ) 即 ( B[rt] ) 就是答案;

    然后高维前缀和求子集的 ( f ) 和,注意最值反演的符号要一开始就带上。

    代码如下:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    int rd()
    {
      int ret=0,f=1; char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return f?ret:-ret;
    }
    int const xn=20,xm=(1<<18)+5,mod=998244353;
    int n,rt,sid[xn][xn],bin[xn],cnt[xm],K[xn],B[xn],d[xn],f[xm];
    ll pw(ll a,int b){a%=mod; ll ret=1; for(;b;b>>=1,a=a*a%mod)if(b&1)ret=ret*a%mod; return ret;}
    int upt(int x){while(x>=mod)x-=mod; while(x<0)x+=mod; return x;}
    void dfs(int x,int fa,int s)
    {
      if(s&bin[x-1]){K[x]=B[x]=0; return;}
      int ks=0,bs=0;
      for(int u=1;u<=n;u++)
        if(sid[x][u]&&u!=fa)
          dfs(u,x,s),ks=upt(ks+K[u]),bs=upt(bs+B[u]);
      K[x]=pw(d[x]-ks,mod-2); B[x]=(ll)(bs+d[x])*pw(d[x]-ks,mod-2)%mod;
    }
    int main()
    {
      n=rd(); int Q=rd(); rt=rd();
      for(int i=1,x,y;i<n;i++)x=rd(),y=rd(),sid[x][y]=sid[y][x]=1,d[x]++,d[y]++;
      bin[0]=1; for(int i=1;i<=n;i++)bin[i]=(bin[i-1]<<1);
      for(int s=1;s<bin[n];s++)cnt[s]=cnt[s>>1]+(s&1);
      for(int s=1;s<bin[n];s++)
        {
          memset(K,0,sizeof K); memset(B,0,sizeof B);
          dfs(rt,0,s); f[s]=upt(((cnt[s]&1)?1:-1)*B[rt]);//
        }
      for(int i=1;i<=n;i++)
        for(int s=0;s<bin[n];s++)
          if(s&bin[i-1])f[s]=upt(f[s]+f[s^bin[i-1]]);
      for(int i=1,k,s;i<=Q;i++)
        {
          k=rd(); s=0;
          for(int j=1,x;j<=k;j++)x=rd(),s|=bin[x-1];
          printf("%d
    ",f[s]);
        }
      return 0;
    }
  • 相关阅读:
    VS2010 自动跳过代码现象
    Reverse Linked List II 【纠结逆序!!!】
    Intersection of Two Linked Lists
    Linked List Cycle II
    Remove Nth Node From End of List 【另一个技巧,指针的指针】
    Swap Nodes in Pairs
    Merge Two Sorted Lists
    Remove Duplicates from Sorted List
    Linked List Cycle
    Dungeon Game
  • 原文地址:https://www.cnblogs.com/Zinn/p/10279681.html
Copyright © 2011-2022 走看看