Codeforces 1097G

根本想不到ios

CF1097Ggit


題意

給出一棵樹,定義f(S)爲用最少的邊連通點集$ S$的邊數spa

求$ \sum\limits f(S)^k$code

$ n \leq 10^5 k \leq 200$blog


題解

假設$ k=1$有一個清真的樹形$ DP$get

在點集的$ LCA$處統計答案便可string

對於$ k>1$根據二項式定理it

能夠$ O(nk^2)$完成轉移io

但這是過不去的class

考慮

$$ x^k=\sum_{i=0}^k \binom{x}{i}S(k,i)i!$$

其中$ S(i,j)$表示第二類斯特林數

拆開組合數得

$$ x^k=\sum_{i=0}^k \frac{x!}{(x-i)!}S(k,i)$$

所以咱們只要維護全部的降低冪就能夠還原出$ x^k$

誒等等...這複雜度仍是$ nk^2$的啊...

冷靜分析一下,假設當前選取的邊集大小不超過$ k$那降低冪爲$ 0$

所以咱們只須要枚舉到$ min(當前非0降低冪的長度,k)$便可

根據樹上揹包的複雜度分析,實際上是$ O(nk)$的


代碼

#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#define p 1000000007
#define rt register int
#define ll long long
using namespace std;
inline ll read(){
    ll x=0;char zf=1;char ch=getchar();
    while(ch!='-'&&!isdigit(ch))ch=getchar();
    if(ch=='-')zf=-1,ch=getchar();
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();return x*zf;
}
void write(ll y){if(y<0)putchar('-'),y=-y;if(y>9)write(y/10);putchar(y%10+48);}
void writeln(const ll y){write(y);putchar('\n');}
int k,m,n,x,y,z,cnt;
vector<int>e[100010];
int S[205][205],f[100100][205],mi[100010],sz[100010],ans[100010];
void dfs(int x,int pre){
    f[x][0]=sz[x]=1;
    for(auto v:e[x])if(v!=pre){
        dfs(v,x);
        for(rt i=min(sz[v]-1,k-1);i>=0;i--){
            int val=f[v][i];
            if(!i)val=1ll*val*(1-mi[sz[v]])%p;
            (ans[i+1]+=1ll*val*(1-mi[n-sz[v]])%p)%=p;
            (f[v][i+1]+=val)%=p;
        }
        for(rt i=min(sz[x]-1,k);i>=0;i--)
        for(rt j=1;j<=sz[v]&&i+j<=k;j++){
            const int val=1ll*f[x][i]*f[v][j]%p;
            if(i)(ans[i+j]+=val)%=p;
            (f[x][i+j]+=val)%=p;
        }
        sz[x]+=sz[v];
    }
}
#define inv2 500000004
int main(){
    n=read(),k=read();
    S[0][0]=1;
    for(rt i=1;i<=k;i++)
    for(rt j=1;j<=i;j++)S[i][j]=(S[i-1][j-1]+1ll*S[i-1][j]*j%p)%p;    
    for(rt i=1;i<n;i++){
        x=read();y=read();
        e[x].push_back(y);
        e[y].push_back(x);
    }
    mi[0]=1;
    for(rt i=1;i<=n;i++)mi[i]=1ll*mi[i-1]*inv2%p;
    dfs(1,0);
    int ret=0,jc=1;
    for(rt i=0;i<=k;i++)(ret+=1ll*S[k][i]*jc%p*ans[i]%p)%=p,jc=1ll*jc*(i+1)%p;
    for(rt i=1;i<=n;i++)ret=2ll*ret%p;
    cout<<(ret+p)%p;
    return 0;
}
相關文章
相關標籤/搜索