LUOGU 5296:[北京合宿2019地方の選挙]数ガウス+マトリックス - スパニングツリー

タイトル

LUOGU 5296

説明

与えられた(N- \)\を加重ポイント無向完全グラフ、ツリースパニング全ての重みを見つける\(K \)の電力和番目を。
木の重み、重みとそのすべてのエッジの定義。
答えは大きいかもしれないので、してください出力への回答(998 244 353 \)\の結果を法。

分析

参考:hec0411

その答えは、おそらく最初の式を列挙されています。

セット\(E \)は、スパニングツリー、我々列挙の辺集合です。
\ [回答= \ sum_ {E }(\ sum_ {iはEで\} w_i)^ K \\ = \ sum_E \のprod_ {iはEで\} \ binom {K} {a_iを} w_i ^ {a_iを} [\ sum_ {iはEで\} a_iを = K] \\ = \ sum_E \ FRAC {1} {K!} \ prod_ {iはEで\} \ FRAC {1} {a_iを!} w_i ^ {a_iを} [\ sum_ a_iを= {iがEで\} ] K \]

キルヒホッフ行列を決定することができる:
\ [W_i \で\ sum_ {E} \ {IはEを\ prod_}]

上記の式のために、我々は、各辺が多項式が実際にあることが判明:
\ [I W(X)= \ sum_ {I} = 0 ^ K \ FRAC 1} W {I ^ \ {!}]

だから、最終的な答えは、多項式で見つけることができるでしょうです(N- * k個\)\

私たちはより大きなに収まることができる\(N * K + 1 \は ) ラグランジュ補間を用い、その後、カウントの兄マトリックスのツリー定理に対応し、その算出値に値\(K \)項の係数を、私はガウスの消去がうまくやるようだと思います。

時間の複雑さはおよそ次のとおりです\(O(N-4K ^)\)

コード

#include<bits/stdc++.h>

typedef long long ll;
const int maxn=31,mod=998244353;
typedef ll lar1[maxn*maxn];
typedef ll lar2[maxn][maxn];

namespace IO
{
    char buf[1<<15],*fs,*ft;
    inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
    template<typename T>inline void read(T &x)
    {
        x=0;
        T f=1, ch=getchar();
        while (!isdigit(ch) && ch^'-') ch=getchar();
        if (ch=='-') f=-1, ch=getchar();
        while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
        x*=f;
    }

    char Out[1<<24],*fe=Out;
    inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
    template<typename T>inline void write(T x,char str)
    {
        if (!x) *fe++=48;
        if (x<0) *fe++='-', x=-x;
        T num=0, ch[20];
        while (x) ch[++num]=x%10+48, x/=10;
        while (num) *fe++=ch[num--];
        *fe++=str;
    }
}

using IO::read;
using IO::write;

inline ll Quick_power(ll a,ll b)
{
    ll ans=1;
    while (b)
    {
        if (b&1) ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans;
}

inline ll Gauss(ll a[maxn][maxn],int n)
{
    ll ans=1;
    for (int k=2; k<=n; ++k)
    {
        for (int i=k; i<=n; ++i)
            if (a[i][k])
            {
                if (k^i) ans=ans*(mod-1)%mod, std::swap(a[k],a[i]);
                break;
            }
        ans=ans*a[k][k]%mod;
        ll INV=Quick_power(a[k][k],mod-2);
        for (int i=k+1; i<=n; ++i)
        {
            ll tmp=INV*a[i][k]%mod;
            for (int j=k; j<=n; ++j) a[i][j]=(a[i][j]-tmp*a[k][j]%mod+mod)%mod;
        }
    }
    return ans;
}

int m;
lar1 f,h,fac,inv;
inline void Add(int x)
{
    for (int i=m; i>=0; --i)
    {
        h[i]=h[i]*(mod-x)%mod;
        if (i) (h[i]+=h[i-1])%=mod;
    }
}

inline void Del(int x)
{
    for (int i=0; i<=m; ++i)
    {
        if (i) h[i]=h[i]-h[i-1]+mod;
        h[i]=h[i]*Quick_power(mod-x,mod-2)%mod;
    }
}

lar2 w,val,a;
ll g[maxn][maxn][maxn];
int main()
{
    int n,k;read(n);read(k);
    m=n*k+3;
    fac[0]=1;
    for (int i=1; i<=m; ++i) fac[i]=fac[i-1]*i%mod;
    inv[m]=Quick_power(fac[m],mod-2);
    for (int i=m-1; i>=0; --i) inv[i]=inv[i+1]*(i+1)%mod;

    for (int i=1; i<=n; ++i)
        for (int j=1; j<=n; ++j) read(w[i][j]);
    for (int i=1; i<=n; ++i)
        for (int j=i+1; j<=n; ++j)
            for (int t=0; t<=k; ++t) g[i][j][t]=Quick_power(w[i][j],t)*inv[t]%mod;

    for (int x=1; x<=m; ++x)
    {
        for (int i=1; i<=n; ++i)
            for (int j=i+1; j<=n; ++j)
            {
                val[i][j]=0;
                ll now=1;
                for (int t=0; t<=k; ++t) (val[i][j]+=g[i][j][t]*now)%=mod, now=now*x%mod;
            }
        memset(a,0,sizeof(a));
        for (int i=1; i<=n; ++i)
            for (int j=i+1; j<=n; ++j)
            {
                a[i][i]+=val[i][j], a[j][j]+=val[i][j];
                a[i][j]-=val[i][j], a[j][i]-=val[i][j];
            }
        for (int i=1; i<=n; ++i)
            for (int j=1; j<=n; ++j) a[i][j]=(a[i][j]%mod+mod)%mod;
        f[x]=Gauss(a,n);
    }

    h[0]=1;
    for (int i=1; i<=m; ++i) Add(i);
    ll ans=0;
    for (int i=1; i<=m; ++i)
    {
        Del(i);
        ll now=1;
        for (int j=1; j<=m; ++j)
            if (i^j) now=now*(i-j)%mod;
        now=Quick_power(now%mod+mod,mod-2);
        ans=(ans+now*h[k]%mod*f[i])%mod;
        Add(i);
    }
    write(ans*fac[k]%mod,'\n');
    IO::flush();
    return 0;
}

おすすめ

転載: www.cnblogs.com/G-hsm/p/11440231.html