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\neq0)\)

其中对于\(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\neq0\ \&\&\ j\neq0\),那么这\(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}\)

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

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

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

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

由二项式定理知,原式=\(3\sum_{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;
}
posted @ 2018-12-21 10:59  EncodeTalker  阅读(443)  评论(0编辑  收藏  举报