[bzoj5093]图的价值

[bzoj5093]图的价值


每个点计算贡献,有n-1的点的图的总数,然后若干次方转成下降幂再斯特林数求行就能统计答案了。

  • 代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
typedef long long ll;

const int mod=998244353;
int add(int a,int b){a+=b;return a>=mod?a-mod:a;}
int sub(int a,int b){a-=b;return a<0?a+mod:a;}
int mul(int a,int b){return (ll)a*b%mod;}
int qpow(int a,int b){int ret=1;for(;b;b>>=1,a=mul(a,a))if(b&1)ret=mul(ret,a);return ret;}
int mul(int a,int b,int mod){return (ll)a*b%mod;}
int qpow(int a,int b,int mod){int ret=1;for(;b;b>>=1,a=mul(a,a,mod))if(b&1)ret=mul(ret,a,mod);return ret;}
/*math*/

namespace Template_Poly{
    const int g=3;
    typedef vector<int> Poly;
    int rev[N];
    Poly Poly_add(Poly A,Poly B){
        A.resize(max(A.size(),B.size()));
        for(size_t i=0;i<B.size();i++)A[i]=add(A[i],B[i]);
        return A;
    }
    void DFT(int *t,int n,int type){
        int l=0;while(1<<l<n)++l;
        for(int i=0;i<n;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
        for(int i=0;i<n;i++)if(rev[i]>i)swap(t[rev[i]],t[i]);
        for(int step=1;step<n;step<<=1){
            int wn=qpow(g,(mod-1)/(step<<1));
            for(int i=0;i<n;i+=step<<1){
                int w=1;
                for(int k=0;k<step;k++,w=mul(w,wn)){
                    int x=t[i+k],y=mul(t[i+k+step],w);
                    t[i+k]=add(x,y),t[i+k+step]=sub(x,y);
                }
            }
        }
        if(type==1)return;
        for(int i=1;i<n-i;i++)swap(t[i],t[n-i]);
        int inv=qpow(n,mod-2);
        for(int i=0;i<n;i++)t[i]=mul(t[i],inv);
    }
    Poly NTT(Poly A,int n,Poly B,int m){
        static Poly res,PolA,PolB;
        PolA=A,PolB=B;
        int len=1;while(len <= n+m)len<<=1;
        res.resize(len);
        PolA.resize(len),PolB.resize(len);
        DFT(&PolA[0],len,1);DFT(&PolB[0],len,1);
        for(int i=0;i<len;i++) res[i]= mul(PolA[i],PolB[i]);
        DFT(&res[0],len,-1);
        res.resize(n+m-1);
        return res;
    }
    Poly NTT(Poly A,Poly B){
        return NTT(A,A.size(),B,B.size());
    }
    Poly Poly_inv(Poly A,int n){
        if(n==1)return Poly(1,qpow(A[0],mod-2));
        int len=1<<((int)ceil(log2(n))+1);
        Poly x=Poly_inv(A,(n+1)>>1),y;
        x.resize(len),y.resize(len);
        for(int i=0;i<n;i++)y[i]=A[i];
        DFT(&x[0],len,1),DFT(&y[0],len,1);
        for(int i=0;i<len;i++)x[i]=mul(x[i],sub(2,mul(x[i],y[i])));
        DFT(&x[0],len,-1);
        x.resize(n);
        return x;
    }
    Poly Poly_inv(Poly A){
        return Poly_inv(A,A.size());
    }
    Poly Deri(Poly A){
        int n=A.size();
        for(int i=1;i<n;i++)A[i-1]=mul(A[i],i);
        A.resize(n-1);
        return A;
    }

    Poly Inte(Poly A){
        int n=A.size();
        A.resize(n+1);
        for(int i=n;i;i--)A[i]=mul(A[i-1],qpow(i,mod-2));
        A[0]=0;
        return A;
    }

    Poly ln(Poly A){
        int len=A.size();
        A=Inte(NTT(Deri(A),Poly_inv(A)));
        A.resize(len);
        return A;
    }

    Poly exp(Poly A,int n){
        if(n==1)return Poly(1,1);
        Poly x=exp(A,(n+1)>>1),y;
        x.resize(n);
        y=ln(x);
        for(int i=0;i<n;i++)y[i]=sub(A[i],y[i]);
        y[0]++;
        x=NTT(x,y);
        x.resize(n);
        return x;
    }
    Poly exp(Poly A){
        return exp(A,A.size());
    }

    Poly sqrt(Poly A,int n){
        if(n==1)return Poly(1,1);
        Poly x=sqrt(A,(n+1)>>1),y;
        x.resize(n),y.resize(n);
        for(int i=0;i<n;i++)y[i]=A[i];
        x=Poly_add(NTT(Poly_inv(x),y),x);
        int inv2=qpow(2,mod-2);
        for(int i=0;i<n;i++)
            x[i]=mul(x[i],inv2);
        x.resize(n);
        return x;
    }
    Poly sqrt(Poly A){
        return sqrt(A,A.size());
    }
}
using namespace Template_Poly;
typedef long long ll;
int n,k;
int f[N*2];
Poly L,R;
Poly S;
int main()
{
    scanf("%d%d",&n,&k);
    L.resize(k+1);R.resize(k+1);
    int _A=1;
    int _fac=1;
     for(int i=0;i<=k;i++){
        if(i>0)_A=mul(_A,n-i);
        if(i>0)_fac=mul(_fac,qpow(i,mod-2));
        if(i>n-1)break;
        int comb=mul(_A,_fac);
        f[i]=mul(comb,qpow(2,n-i-1));
    }
    _fac=1;
    for(int i=0;i<=k;i++){
        if(i>0){
        _fac=mul(_fac,qpow(i,mod-2));_fac=sub(0,_fac);
        }L[i]=_fac;
    }
    _fac=1;
    for(int i=0;i<=k;i++){
        if(i>0)_fac=mul(_fac,qpow(i,mod-2));
        R[i]=mul(_fac,qpow(i,k));
    }
    S=NTT(L,R);
    int fac=1;
    int ans=0;
    for(int i=0;i<=k;i++){
        if(i>0)fac=mul(fac,i);
        ans=add(ans,mul(fac,mul(f[i],S[i])));
    }
    int ml=qpow(2,mul((n-2)%2?n-2:(n-2)/2,(n-1)%2?(n-1):(n-1)/2,mod-1));
    ans=mul(ans,ml);ans=mul(ans,n);
    printf("%d\n",ans);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值