[CF997C]Sky Full of Stars

# 壹、题目描述 ¶

传送门 to Luogu.

贰、题解 ¶

不难想到对行列同时进行容斥,但是会出现一个问题 —— 当只有行或者只有列的时候,行之间的颜色可以相互独立,而当行列同时具有时,所有的行列颜色都被统一起来了,所以,针对 \(i,j\) 其中一个为 \(0\) 的情况,我们应该特别处理一下,那么,不难有容斥式子:

\[Ans=2\sum_{i=1}^n(-1)^i{n\choose i}3^{n^2-in+i}-\sum_{i=1}^n\sum_{j=1}^n(-1)^{i+j}{n\choose i}{n\choose j}3^{n^2-(i+j)n+ij+1} \]

但是直接对这个式子计算,明眼人都看得出来这是 \(\mathcal O(n^2)\) 的,复杂度无法接受,我们考虑对后面那一坨进行化简:

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

最后不要忘记添上最前面的负号,后面补 \(-1\) 是因为二项式定理是从 \(j=0\) 开始的,但是我们这里并不是,补一项来凑齐。

叁、参考代码 ¶

#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
#include<set>
using namespace std;

#define NDEBUG
#include<cassert>

namespace Elaina{
    #define rep(i, l, r) for(int i=(l), i##_end_=(r); i<=i##_end_; ++i)
    #define drep(i, l, r) for(int i=(l), i##_end_=(r); i>=i##_end_; --i)
    #define fi first
    #define se second
    #define mp(a, b) make_pair(a, b)
    #define Endl putchar('\n')
    #define mmset(a, b) memset(a, b, sizeof a)
    // #define int long long
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    typedef pair<ll, ll> pll;
    template<class T>inline T fab(T x){ return x<0? -x: x; }
    template<class T>inline void getmin(T& x, const T rhs){ x=min(x, rhs); }
    template<class T>inline void getmax(T& x, const T rhs){ x=max(x, rhs); }
    template<class T>inline T readin(T x){
        x=0; int f=0; char c;
        while((c=getchar())<'0' || '9'<c) if(c=='-') f=1;
        for(x=(c^48); '0'<=(c=getchar()) && c<='9'; x=(x<<1)+(x<<3)+(c^48));
        return f? -x: x;
    }
    template<class T>inline void writc(T x, char s='\n'){
        static int fwri_sta[1005], fwri_ed=0;
        if(x<0) putchar('-'), x=-x;
        do fwri_sta[++fwri_ed]=x%10, x/=10; while(x);
        while(putchar(fwri_sta[fwri_ed--]^48), fwri_ed);
        putchar(s);
    }
}
using namespace Elaina;

const int mod=998244353;
const int maxn=1e6;

inline int qkpow(int a, ll n){
    int ret=1;
    for(; n>0; n>>=1, a=1ll*a*a%mod)
        if(n&1) ret=1ll*ret*a%mod;
    return ret;
}

int fac[maxn+5], finv[maxn+5];
inline void prelude(){
    fac[0]=finv[0]=1;
    for(int i=1; i<=maxn; ++i)
        fac[i]=1ll*fac[i-1]*i%mod;
    finv[maxn]=qkpow(fac[maxn], mod-2);
    for(int i=maxn-1; i>=1; --i)
        finv[i]=1ll*finv[i+1]*(i+1)%mod;
}
inline int C(int n, int m){
    if(n<m) return 0;
    return 1ll*fac[n]*finv[m]%mod*finv[n-m]%mod;
}

int n, ans=0;

#define sign(i) (((i)&1)? -1: 1)
signed main(){
    prelude();
    n=readin(1);
    for(int i=1; i<=n; ++i)
        ans=(ans+1ll*sign(i-1)*C(n, i)*qkpow(3, 1ll*n*n-1ll*i*n+i)%mod)%mod;
    ans=2ll*ans%mod;
    int inv3=qkpow(3, mod-2);
    for(int i=1; i<=n; ++i){
        int part1=1ll*sign(i)*C(n, i)*qkpow(3, 1ll*n*n-1ll*i*n+1)%mod;
        int part2=(qkpow((1+mod-qkpow(inv3, n-i))%mod, n)+mod-1)%mod;
        ans=(0ll+ans+mod-1ll*part1*part2%mod)%mod;
    }
    writc(ans);
    return 0;
}
posted @ 2021-08-06 08:14  Arextre  阅读(34)  评论(0编辑  收藏  举报