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

  

posted @ 2020-07-24 09:08  EM-LGH  阅读(158)  评论(0编辑  收藏  举报