题面
给一个 n*m 的矩阵染色, 每个点可以染 k 种颜色, 求没有任意一行或任意一列颜色相同的方案数。答案对 998244353 取模。
容斥。
枚举有 i 行 j 列同色的方案数,并乘上 加入答案。//容斥原理,有加有减
令 f(i; j) 为 i 行 j 列同色,同色的行列所能取的颜色方案数。
i = 0; j = 0 时, f(i; j) = 1 //没有点,自然只有一种选择。
i = 0; j > 0 时, f(i; j) = //只有列有同色,每一列有k种选择,共j列
i > 0; j = 0 时, f(i; j) = //同上
i > 0; j > 0 时, f(i; j) = k //这i行j列颜色都一样,只有k种选择
答案为 * * f(i; j) *
对于 i = 0 或 j = 0 的情况可以暴力计算,考虑 i 和 j 都大于 0 的情况。
k **
= k ·
= k ·
= k ( - )
就可以利用快速幂计算了。
代码
#include
using namespace std;
const long long MOD=998244353,MOD2=MOD-1;
const int N=1010000;
long long n,m,k,fac[N],inv[N];
long long pow(long a,long b){//快速幂
a=(a%MOD+MOD)%MOD,b=(b%MOD2+MOD)%MOD2;
long long r=1;
while(b){
if(b&1) r=r*a%MOD;
a=a*a%MOD,b<<=1;
}
return r;
}
long long C(int n,int m){//组合数
if(n<0||m<0||n-m<0) return;
return fac[n]*inv[m]%MOD*inv[n-m]%MOD;
}
int main(){
fac[0]=1;
for(int i=1;i<=1000000;i++)
fac[i]=fac[i-1]*i%MOD;//阶乘
inv[0]=inv[1]=1;//逆元
for(int i=2;i<=1000000;i++)
inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD;
for(int i=1;i<=1000000;i++)
inv[i]=inv[i-1]*inv[i]%MOD;
cin>>n>>m>>k;
long long ans=pow(k,n*m);//所有的情况
for(int i=1;i<=n;i++)//暴力求只有横行同色
if(i&1)//容斥原理,奇减偶加
ans=(ans-C(n,i)*pow(k,i)%Mod*pow(k,(n-i)*m)%MOD+MOD)%MOD;
else
ans=(ans+C(n,i)*pow(K,i)%MOD*pow(K,(n-i)*m)%MOD)%MOD;
for(int i=1;i<=m;i++)//暴力求只有竖列同色
if(i&1)
ans=(ans-C(m,i)*pow(K,i)%MOD*pow(K,(m-i)*n)%MOD+MOD)%MOD;
else
ans=(ans+C(m,i)*pow(K,i)%MOD*pow(K,(m-i)*n)%MOD)%MOD;
for(int i=1;i<=n;i++)//求既有行又有列同色
if(i&1)
ans=(ans-C(n,i)*K%MOD*((pow(pow(K,n-i)-1,m)-pow(K,(n-i)*m)+MOD)%MOD)%MOD+MOD)%MOD;
else
ans=(ans+C(n,i)*K%MOD*((pow(pow(K,n-i)-1,m)-pow(K,(n-i)*m)+MOD)%MOD)%MOD)%MOD;
cout<