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; }