竞赛图强连通分量大小幂和计数 - 组合计数 - 多项式

题目大意:求所有 n n n个点带标号竞赛图的强连通分量大小的 k k k次方之和的和,对 9982443535 9982443535 9982443535模数取模。 n ≤ 1 0 5 , k ≤ 998244352 n\le10^5,k\le 998244352 n105,k998244352
题解:
竞赛图缩点后拓扑序唯一(其实是链状结构然后剩下的两端不在同一个强连通分量里面的边的方向是确定的)。
g n g_n gn表示答案, f n f_n fn表示 n n n个点的能够缩成一个点的竞赛图数量, h n = 2 ( n 2 ) h_n=2^{\binom{n}{2}} hn=2(2n)就是图的总数。
那么求 g g g显然是,你枚举拓扑序最后一坨点的大小,钦定它们是一个 S C C SCC SCC
g n = ∑ i = 1 n ( n i ) ( h n − i i k + g n − i ) f i g_n=\sum_{i=1}^n \binom ni \left(h_{n-i}i^k+g_{n-i}\right)f_i gn=i=1n(in)(hniik+gni)fi
f f f更简单,用总数减去不合法的即可:
f n = h n − ∑ i = 1 n − 1 ( n i ) h n − i f i f_n=h_n-\sum_{i=1}^{n-1}\binom{n}{i}h_{n-i}f_i fn=hni=1n1(in)hnifi
这样就可以做到 O ( n 2 ) O\left(n^2\right) O(n2)
接下来开始多项式的套路:
首先关于 f f f,有:
h n = ∑ i = 1 n ( n i ) f i h n − i = ∑ i = 0 n ( n i ) f i h n − i + [ n = = 0 ] h_n=\sum_{i=1}^n\binom nif_ih_{n-i}=\sum_{i=0}^n\binom nif_ih_{n-i}+[n==0] hn=i=1n(in)fihni=i=0n(in)fihni+[n==0]并钦定 f 0 = 0 f_0=0 f0=0
那么令:
H ( x ) = ∑ i ≥ 0 h i i ! x i , F ( x ) = ∑ i ≥ 1 f i i ! x i H(x)=\sum_{i\geq 0}\frac {h_i}{i!}x^i,F(x)=\sum_{i\geq1}\frac{f_i}{i!}x^i H(x)=i0i!hixi,F(x)=i1i!fixi
那么 H = F H + 1 , F = 1 − H − 1 H=FH+1,F=1-H^{-1} H=FH+1,F=1H1
然后由之前的式子,令:
G ( x ) = ∑ i ≥ 1 g i i ! x i , T ( x ) = ∑ i ≥ 1 f i i k i ! x i G(x)=\sum_{i\geq1}\frac{g_i}{i!}x^i,T(x)=\sum_{i\geq1}\frac{f_ii^k}{i!}x^i G(x)=i1i!gixi,T(x)=i1i!fiikxi
则: G = H T + G F , ( 1 − F ) G = H T , G = H T 1 − F = H T H − 1 = H 2 T G=HT+GF,(1-F)G=HT,G=\frac{HT}{1-F}=\frac{HT}{H^{-1}}=H^2T G=HT+GF,(1F)G=HT,G=1FHT=H1HT=H2T

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lint long long
#define p 998244353
#define N 300010
#define clr(a,n) memset(a,0,sizeof(int)*((n)+1))
#define cpy(a,b,n) memcpy(a,b,sizeof(int)*((n)+1))
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
int f[N],g[N],h[N],mi[N],fac[N],facinv[N],H[N],T[N],F[N],G[N];
inline int fast_pow(int x,lint k,int ans=1) { for(;k;k>>=1,x=(lint)x*x%p) (k&1)?ans=(lint)ans*x%p:0;return ans; }
inline int C(int n,int m) { if(n<0||m<0||n<m) return 0;return (lint)fac[n]*facinv[m]%p*facinv[n-m]%p; }
inline int prelude(int n)
{
    rep(i,fac[0]=1,n) fac[i]=(lint)fac[i-1]*i%p;
    facinv[n]=fast_pow(fac[n],p-2);
    for(int i=n-1;i>=0;i--) facinv[i]=facinv[i+1]*(i+1ll)%p;
    return 0;
}
namespace NTT_space{
    int a[N<<3],b[N<<3],r[N<<3];
    inline int NTT(int *a,int n,int s)
    {
        rep(i,1,n-1) if(i<r[i]) swap(a[i],a[r[i]]);
        for(int i=2;i<=n;i<<=1)
        {
            int wn=fast_pow(3,s>0?(p-1)/i:p-1-(p-1)/i);
            for(int j=0,t=i>>1;j<n;j+=i)
                for(int k=0,w=1,x,y;k<t;k++,w=(lint)w*wn%p)
                    x=a[j+k],y=(lint)w*a[j+k+t]%p,
                    a[j+k]=x+y,(a[j+k]>=p?a[j+k]-=p:0),
                    a[j+k+t]=x-y,(a[j+k+t]<0?a[j+k+t]+=p:0);
        }
        if(s<0) for(int i=0,ninv=fast_pow(n,p-2);i<n;i++) a[i]=(lint)a[i]*ninv%p;
        return 0;
    }
    inline int tms(int *A,int *B,int *C,int m1,int m2)
    {
        int n=1,L=0;for(;n<=m1+m2;n<<=1,L++);
        rep(i,1,n-1) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
        clr(a,n),cpy(a,A,m1),NTT(a,n,1);
        clr(b,n),cpy(b,B,m2),NTT(b,n,1);
        rep(i,0,n-1) a[i]=(lint)a[i]*b[i]%p;
        return NTT(a,n,-1),cpy(C,a,m1+m2),0;
    }
    inline int tms(int *A,int *B,int *C,int n) { return tms(A,B,C,n,n); }
}
using NTT_space::tms;
namespace POLYINV_space{
    int f[N<<3],g[N<<3],h[N<<3];
    inline int polyinv(int *F,int *G,int m)
    {
        int n=1;while(n<m) n<<=1;
        clr(f,n),cpy(f,F,m),clr(g,n),g[0]=fast_pow(f[0],p-2);
        for(int i=2;i<=n;i<<=1)
        {
            rep(j,0,i>>1) h[j]=g[j]<<1,(h[j]>=p?h[j]-=p:0);
            tms(g,g,g,i>>1),tms(g,f,g,i);
            rep(j,0,i-1) g[j]=h[j]-g[j],(g[j]<0?g[j]+=p:0);
            clr(g+i,i);
        }
        return cpy(G,g,m),0;
    }
}
using POLYINV_space::polyinv;
int main()
{
    int n,k;scanf("%d%d",&n,&k);prelude(n);
    rep(i,0,n) h[i]=fast_pow(2,i*(i-1ll)/2),H[i]=(lint)h[i]*facinv[i]%p,mi[i]=fast_pow(i,k);
//	rep(i,1,n) { f[i]=h[i];for(int j=1;j<i;j++) f[i]-=(lint)f[j]*h[i-j]%p*C(i,j)%p,(f[i]<0?f[i]+=p:0); } rep(i,1,n) F[i]=(lint)f[i]*facinv[i]%p;
//	rep(i,1,n) rep(j,1,i) g[i]+=(lint)f[j]%p*(g[i-j]+(lint)mi[j]*h[i-j]%p)%p*C(i,j)%p,(g[i]>=p?g[i]-=p:0);printf("%d\n",g[n]);
    polyinv(H,F,n);rep(i,0,n) F[i]=(p-F[i])%p;(F[0]+=1)%=p; rep(i,1,n) T[i]=(lint)F[i]*mi[i]%p;
    tms(H,H,H,n),tms(H,T,G,n);return !printf("%lld\n",(lint)G[n]*fac[n]%p);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值