codeforces 997C.Sky Full of Stars

题目链接:codeforces 997C.Sky Full of Stars

一道很简单(?)的推式子题

直接求显然不现实,我们考虑容斥

(f(i,j))为该方阵中至少有(i)行和(j)列为相同颜色的情况

那么显然有(ans=sum_{i=0}^n sum_{j=0}^n C_n^i C_n^j (-1)^{i+j-1} f(i,j) (i+j eq0))

其中对于(f(i,j))的取值有两种情况

​ I.若(i=0)(j=0),先假设(i=0),那么颜色相同的(j)列的颜色可以随意变化,故(f(i,j)=f(0,j)=3^j*3^{n(n-j)})

​ II.若(i eq0 && j eq0),那么这(i)行和(j)列的颜色一定是相同的,故(f(i,j)=3*3^{(n-i)(n-j)})

对于I,我们可以在(O(nlogn))的时间内求出结果

对于II,我们可以通过预处理在(O(n^2))的时间内求出结果,但这显然是不可行的,于是我们考虑变形

根据3的幂次我们令(i=n-i,j=n-j)

那么原式=(sum_{i=0}^{n-1} sum_{j=0}^{n-1} C^{n-i}_n C^{n-j}_n (-1)^{2n-i-j-1} 3*3^{ij})

=(3sum_{i=0}^{n-1} sum_{j=0}^{n-1} C^{i}_n C^{j}_n (-1)^{i+j+1} 3^{ij})

这样做的话仍然没有结束,我们考虑将(i)提出来

原式=(3sum_{i=0}^{n-1} C_n^i (-1)^{i+1} sum_{j=0}^{n-1} C_n^j (-1)^j 3^{ij})

=(3sum_{i=0}^{n-1} C_n^i (-1)^{i+1} sum_{j=0}^{n-1} C_n^j (-3^i)^j)

由二项式定理知,原式=(3sum_{i=0}^{n-1} C_n^i (-1)^{i+1} [(1+(-3^i))^n-(-3^i)^n])

这样的话我们也能在(O(nlogn))的时间内求出这个值

总时间复杂度(O(nlogn))

#include<iostream>
#include<string>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<vector>
#include<queue>
#include<map>
using namespace std;
#define rep(i,a,b) for (i=a;i<=b;i++)
typedef long long ll;
#define maxd 998244353

ll qpow(ll x,ll y)
{
    ll ans=1,sum=x;
    while (y)
    {
        int tmp=y%2;y/=2;
        if (tmp) ans=(ans*sum)%maxd;
        sum=(sum*sum)%maxd;
    }
    return ans;
}

int n;
ll c[1001000],inv[1001000];

int read()
{
    int x=0,f=1;char ch=getchar();
    while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    return x*f;
}

void init()
{
    n=read();int i;
    c[0]=1;inv[1]=1;
    for (i=2;i<=n;i++) inv[i]=((maxd-maxd/i)*inv[maxd%i])%maxd;
    for (i=1;i<=n;i++) c[i]=((c[i-1]*(n-i+1))%maxd*inv[i])%maxd;
    //for (i=1;i<=n;i++) cout << c[i] << " ";cout << endl;
}

void work()
{
    ll ans=0,ans1=0,ans2=0;int i;
    for (i=1;i<=n;i++)
    {
        if (i%2) ans1+=(c[i]*qpow(3,(ll)n*(n-i)+i))%maxd;
        else ans1-=(c[i]*qpow(3,(ll)n*(n-i)+i))%maxd;
    }
    for (i=0;i<n;i++)
    {
        if (i%2) ans2+=(c[i]*(qpow(1+maxd-qpow(3,i),n)-qpow(maxd-qpow(3,i),n))%maxd)%maxd;
        else ans2-=(c[i]*(qpow(1+maxd-qpow(3,i),n)-qpow(maxd-qpow(3,i),n))%maxd)%maxd;
    }
    ans1=((ans1%maxd)+maxd)%maxd;
    ans2=((ans2%maxd)+maxd)%maxd;
    ans=(ans1*2+ans2*3)%maxd;
    printf("%I64d",ans);
}

int main()
{
    init();
    work();
    return 0;
}
原文地址:https://www.cnblogs.com/encodetalker/p/10154563.html