题目链接: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;
}