LOJ2542「PKUWC2018」随机游走

好颓啊好颓啊。这样下去可布星。

让我们继续愉(beng)快(kui)地推柿子吧

对于这个题 我们看见$N=18$就可以意识到事情不妙(

我们看到这个题求的是对于一个集合最后出现的元素游走的期望次数 显然就是min-max容斥

我们先上定义式

$E(max{S})=\sum_{\varnothing \neq T\subseteq S} E(min{T}) (-1) ^{|T|+1}$

上头那个符号是真子集吧(希望不要身败名裂

就转换为我们去枚举它的所有子集来计算随机游走走到T中任意元素就停止的期望

这个玩意好像也不是很好求 我们先画个柿子

$f(x)=\frac{1}{d[x]}\sum _ {E_{x,y}=1} f(y)+1$

当然这个情况是x不在我们枚举的$S$里 当$x$在$S$中时$f(x)$显然等于0

然后呢 由于是树形结构 我们把fa给提出来

$f(x)=1+ \frac{1}{d[x]}f(fa[x]) + \frac{1}{d[x]} \sum _ f(son[x])$

我们接下来干一些奇怪的事情

我们把$f(x)$表示成$f(x)=kf(fa[x])+b$

就是一个系数+一个常数的形式

然后呢 令$y=son[x]$

我们就有

$\sum f(y) = \sum k_yf(x)+b_y$

把它再代入回去

$f(x) = 1+\frac{1}{d[x]} f(fa[x]) + \sum k_yf(x)+b_y$

$(1-\frac{\sum k_y}{d[x]} )f(x) = \frac{1}{d[x]} f(fa[x]) + (1+\frac{\sum b_y}{d[x]})$

把左边的系数除过去接着可以得到$k_x$ 和 $b_x$

这样的话我们就可以通过搜索递推来得到每个$k_x$ 和 $b_x$

然后询问部分需要对其求子集和 那么我们可以用FWT处理

这样的话就做完啦

代码。

//Love and Freedom.
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<vector>
#define ll long long
#define inf 20021225
#define N 19
#define mdn 998244353
#define lowbit(x) (x&-x)
using namespace std;
int read()
{
    int s=0,f=1; char ch=getchar();
    while(ch<'0' || ch>'9')    {if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0' && ch<='9')    s=s*10+ch-'0',ch=getchar();
    return f*s;
}
int ksm(int bs,int mi)
{
    int ans=1;
    while(mi)
    {
        if(mi&1)    ans=1ll*ans*bs%mdn;
        bs=1ll*bs*bs%mdn; mi>>=1;
    }
    return ans;
}
struct edge{int to,lt;}e[N<<1];
int in[N],cnt,k[N],b[N],d[N],f[1<<N];
void add(int x,int y)
{
    e[++cnt].to=y; e[cnt].lt=in[x]; in[x]=cnt;
    e[++cnt].to=x; e[cnt].lt=in[y]; in[y]=cnt;
}
void upd(int &x,int y){x+=x+y>=mdn?y-mdn:y;}
void calc(int x,int fa,int S)
{
    if((S>>(x-1))&1){k[x]=b[x]=0;return;}
    int K,B; K=B=0;
    for(int i=in[x];i;i=e[i].lt)    if(e[i].to!=fa)
    {
        int y=e[i].to; calc(y,x,S);
        upd(K,k[y]); upd(B,b[y]);
    }
    int invd=ksm(d[x],mdn-2);
    int invk=ksm((mdn+1-1ll*K*invd%mdn)%mdn,mdn-2);
    k[x]=1ll*invd*invk%mdn;
    b[x]=(1+1ll*B*invd%mdn)*invk%mdn;
}
void fwt(int lim)
{
    for(int k=2,mid=1;k<=lim;mid<<=1,k<<=1)
        for(int i=0;i<lim;i+=k)    for(int j=0;j<mid;j++)
            upd(f[i+mid+j],f[i+j]);
}
int popcount(int x)
{
    int k=0; while(x)    x-=lowbit(x),k++;
    return k;
}
int main()
{
    int n=read(),q=read(),rt=read();
    int x,y,k;
    for(int i=1;i<n;i++)    x=read(),y=read(),add(x,y),d[x]++,d[y]++;
    int top=1<<n;
    for(int i=0;i<top;i++)
        calc(rt,rt,i),f[i]=popcount(i)&1?b[rt]:-b[rt],f[i]=f[i]<0?f[i]+mdn:f[i];
    fwt(top);
    for(int i=1;i<=q;i++)
    {
        k=read(); int st=0;
        while(k--)    x=read(),st|=1<<x-1;
        printf("%d\n",f[st]);
    }
    return 0;
}
View Code

 

posted @ 2019-07-16 15:00  寒雨微凝  阅读(183)  评论(0编辑  收藏  举报