1. 程式人生 > 實用技巧 >題解 CF997C 【Sky Full of Stars】

題解 CF997C 【Sky Full of Stars】

直接求不好求,考慮用總方案數減去不合法方案數。設 \(f_{i,j}\) 為至少有 \(i\)\(j\) 列顏色相同的方案數,設 \(g_{i,j}\) 為恰好有 \(i\)\(j\) 列顏色相同的方案數,得:

\[\large f(x,y)=\sum_{i=x}^n\sum_{j=y}^n\binom{i}{x}\binom{i}{y}g(i,j) \]

然後發現其可以高維二項式反演,高維反演即為每個維度的反演係數直接乘起來,進行高維二項式反演得:

\[\large g(x,y)=\sum_{i=x}^n\sum_{j=y}^n(-1)^{i+j-x-y}\binom{i}{x}\binom{i}{y}f(i,j) \]

即答案為:

\[\large ans=3^{n^2}-g(0,0) \]

考慮計算 \(f\),得:

\[\large f(i,j) = \begin{cases} \binom{n}{i}\binom{n}{j}3^{(n-i)(n-j)+1} &ij \not = 0 \\ \\ \binom{n}{i+j}3^{n(n-i-j)+i+j} &ij=0,i+j \not =0 \\ \\ 3^{n^2} &i+j=0 \end{cases}\\ \]

當行列都存在相同顏色時,因為行列有交叉部分,所以其只能取同一種顏色,而只有行存在相同顏色或只有列存在相同顏色時,其顏色的選取時不受限制的。

然後計算 \(g(0,0)\)

\[\large\begin{aligned} g(0,0)&=\sum_{i=0}^n\sum_{j=0}^n(-1)^{i+j}f(i,j) \\ &=\sum_{i=1}^n\sum_{j=1}^n(-1)^{i+j}f(i,j)+2\sum_{i=1}^n(-1)^if(i,0)+f_{0,0} \end{aligned} \\ \]

因為第一個和式的原因,直接計算的複雜度是 \(O(n^2)\) 的,無法接受,考慮進行化簡:

\[\large\begin{aligned} &\sum_{i=1}^n\sum_{j=1}^n(-1)^{i+j}f(i,j) \\ =&\sum_{i=1}^n\sum_{j=1}^n(-1)^{i+j}\binom{n}{i}\binom{n}{j}3^{(n-i)(n-j)+1} \\ =&\sum_{i=1}^n(-1)^{i}\binom{n}{i}\sum_{j=1}^n(-1)^{j}\binom{n}{j}3^{n^2-(i+j)n+ij+1} \\ =&3^{n^2+1}\sum_{i=1}^n(-1)^{i}\binom{n}{i}3^{-in}\sum_{j=1}^n\binom{n}{j}(-3^{i-n})^j \\ =&3^{n^2+1}\sum_{i=1}^n(-1)^{i}\binom{n}{i}3^{-in}((1-3^{i-n})^n-1) \\ \end{aligned}\\ \]

最終答案為:

\[\large ans=3^{n^2}-g(0,0)=-3^{n^2+1}\sum_{i=1}^n(-1)^{i}\binom{n}{i}3^{-in}((1-3^{i-n})^n-1)-2\sum_{i=1}^n(-1)^i\binom{n}{i}3^{n(n-i)+i} \]

#include<bits/stdc++.h>
#define maxn 1000010
#define p 998244353
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    if(flag)x=-x;
}
ll n,v1,v2;
ll fac[maxn],ifac[maxn];
ll qp(ll x,ll y)
{
    ll v=1;
    while(y)
    {
        if(y&1) v=v*x%p;
        x=x*x%p,y>>=1;
    }
    return v;
}
ll C(int n,int m)
{
    return fac[n]*ifac[m]%p*ifac[n-m]%p;
}
void init()
{
    fac[0]=ifac[0]=1;
    for(int i=1;i<=n;++i) fac[i]=fac[i-1]*i%p;
    ifac[n]=qp(fac[n],p-2);
    for(int i=n-1;i;--i) ifac[i]=ifac[i+1]*(i+1)%p;
}
int main()
{
    read(n),init();
    for(int i=1;i<=n;++i)
    {
        ll v=C(n,i)*qp(qp(3,i*n),p-2)%p*(qp((1-qp(qp(3,n-i),p-2)+p)%p,n)-1+p)%p;
        if(i&1) v1=(v1-v+p)%p;
        else v1=(v1+v+p)%p;
    }
    for(int i=1;i<=n;++i)
    {
        ll v=C(n,i)*qp(3,n*(n-i)%(p-1)+i)%p;
        if(i&1) v2=(v2-v+p)%p;
        else v2=(v2+v+p)%p;
    }
    printf("%lld",((-qp(3,(n*n+1)%(p-1))*v1%p+p)%p-2*v2%p+p)%p);
    return 0;
}