LuoguP4931 [MtOI2018]情侣?给我烧了!(加强版) 组合
不妨枚举哪些位置和睦,然后计算其他位置都不和睦的方案数.
令 $f[i]$ 表示 $i$ 对情侣都不和睦的方案数.
然后 $f[i]$ 的转移和错位排列比较相似,即让情侣 $(i,i')$ 与 $(x,y)$ 合并或者 $(x,x')$ 合并.
前者对应 $f[i-2] \times 2 \times (i-1)^2 \times i$,后者对应 $f[i-1] \times (i-1) \times 2 \times i$.
最后输出 $\binom{n}{k} ^2 k! \times f[n-k] \times 2^n$ 即可.
code:
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 5000008
#define ll long long
#define mod 998244353
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
int f[N],fac[N],inv[N],pw[N];
int qpow(int x,int y) {
int tmp=1;
for(;y;y>>=1,x=(ll)x*x%mod) {
if(y&1) tmp=(ll)tmp*x%mod;
}
return tmp;
}
int get_inv(int x) {
return qpow(x,mod-2);
}
void init() {
fac[0]=pw[0]=1;
for(int i=1;i<N;++i) {
pw[i]=(ll)pw[i-1]*2%mod;
fac[i]=(ll)fac[i-1]*i%mod;
}
inv[1]=1;
for(int i=2;i<N;++i) {
inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod;
}
inv[0]=1;
for(int i=1;i<N;++i) {
inv[i]=(ll)inv[i-1]*inv[i]%mod;
}
}
int C(int x,int y) {
return (ll)fac[x]*inv[y]%mod*inv[x-y]%mod;
}
int main() {
// setIO("input");
init();
f[0]=1,f[1]=0;
for(int i=1;i<N;++i) {
f[i]=(ll)(i-1)*f[i-2]%mod*2%mod*(i-1)%mod*i%mod;
(f[i]+=(ll)(i-1)*f[i-1]%mod*2%mod*i%mod)%=mod;
}
int T,n,k;
scanf("%d",&T);
while(T--) {
scanf("%d%d",&n,&k);
printf("%d\n",(ll)C(n,k)*C(n,k)%mod*fac[k]%mod*f[n-k]%mod*pw[n]%mod);
}
return 0;
}

浙公网安备 33010602011771号