【题解】AT2064 Many Easy Problems(转换+NTT)

【题解】AT2064 Many Easy Problems(转换+NTT)

给定一棵树,请你回答\(k\in[1,n]\)\(k\)个点生成出来的虚树(steiner)的所有方案的大小的和。

对于这种分元素然后每个元素对答案有一个相同的贡献的计数,一般都是考虑对于一个点考虑对于答案的贡献。对于一个确定的\(k\)和一个点\(p\),可以很轻易的算出\(p\)对于答案的贡献=\({n\choose k }-( \sum_{u \in Son}siz[u])-(n-siz[p])\)。我们拿个同记录相同的组合数的上面的那个数,这个数组设为\(s_i\)那么设答案为\(a_k\),有(\(b_0=0\))
\[ a_k=\sum_{i=0}^n b_i{i\choose k} \]
拆开
\[ a_k=\sum_{i=0} {b_i i!\over k! (i-k)!} \]
随便化一下
\[ k!a_k=\sum_{i} {(b_ii!)\over (i-k)!} \]
按照上次的那种套路搞出来就能NTT了

这一发TLE了,不知道为什么......

upd: AtCoder 编译命令没有-DONLINE_JUDGE

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>

using namespace std;  typedef long long ll;   char __buf[1<<18],*__c=__buf,*__ed=__buf;
inline int qr(){
    int ret=0,f=0,c=getchar();
    while(!isdigit(c))f|=c==45,c=getchar();
    while(isdigit(c)) ret=ret*10+c-48,c=getchar();
    return f?-ret:ret;
}
const int maxn=1<<19|1;
const int mod=998244353;
const int g=3;
const int gi=(mod+1)/3;
typedef vector<int> poly;
poly buk(maxn),c(maxn);
int inv[maxn],siz[maxn],r[maxn],jc[maxn],n;

inline int MOD(const int&x){return x-mod>=0?x-mod:x;}
inline int MOD(const int&x,const int&y){return 1ll*x*y%mod;}
inline int MOD(const vector<int>&ve){int ret=1;for(const auto&t:ve) ret=MOD(ret,t); return ret;}

inline int ksm(const int&ba,const int&p){
    int ret=1;
    for(int t=p,b=ba;t;t>>=1,b=MOD(b,b))
        if(t&1) ret=MOD(ret,b);
    return ret;
}

void pre(const int&n){
    jc[0]=inv[0]=1;
    for(int t=1;t<=n;++t) jc[t]=MOD(jc[t-1],t);
    inv[n]=ksm(jc[n],mod-2);
    for(int t=n-1;t;--t) inv[t]=MOD(inv[t+1],t+1);
    for(int t=1;t<=n;++t)
        if(MOD(jc[t],inv[t])!=1)
            puts("wa");
}

void NTT(poly&a,const int&tag){
    static int r[maxn];
    int len=a.size();
    for(int t=1;t<len;++t)
        if((r[t]=r[t>>1]>>1|(t&1?len>>1:0))>t)
            swap(a[t],a[r[t]]);
    for(int t=1,wn,s=tag==1?g:gi;t<len;t<<=1){
        wn=ksm(s,(mod-1)/(t<<1));
        for(int i=0;i<len;i+=t<<1)
            for(int j=0,w=1,p;j<t;++j,w=MOD(w,wn))
                p=MOD(a[i+j+t],w),a[i+j+t]=MOD(a[i+j]-p+mod),a[i+j]=MOD(a[i+j]+p);
    }
    if(tag!=1)
        for(int t=0,i=mod-(mod-1)/len;t<len;++t)
            a[t]=MOD(a[t],i);
}

poly operator * (poly a,poly b){
    int t1=a.size()+b.size()-1,len=1;
    while(len<t1) len<<=1;
    a.resize(len); b.resize(len);
    NTT(a,1); NTT(b,1);
    for(int t=0;t<len;++t) a[t]=MOD(a[t],b[t]);
    NTT(a,-1); a.resize(t1);
    return a;
}

poly e[maxn];
void add(int fr,int to){
    e[fr].push_back(to);
    e[to].push_back(fr);
}

void dfs(int now,int last){
    siz[now]=1;
    for(auto t:e[now])
        if(t^last)
            dfs(t,now),++buk[siz[t]],siz[now]+=siz[t];
    if(n-siz[now]>=0) ++buk[n-siz[now]];
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("in.in","r",stdin);
    //freopen("out.out","w",stdout);    
#endif
    n=qr();
    buk.resize(n+1);
    c.resize(n+1);
    for(int t=1;t<n;++t) add(qr(),qr());
    dfs(1,0); pre(2e5);
    for(int t=0;t<=n;++t) buk[t]=MOD(buk[t],jc[t]);
    reverse(buk.begin(),buk.end());
    for(int t=0;t<=n;++t) c[t]=inv[t];
    poly ans=buk*c;
    ans.resize(n+1);
    reverse(ans.begin(),ans.end());
    for(int t=1;t<=n;++t) printf("%d\n",MOD(MOD({jc[n],inv[t],inv[n-t],n})-MOD(ans[t],inv[t])+mod));
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/winlere/p/12181215.html