题解 P4931 【情侣?给我烧了!(加强版)】

Linne

2019-01-27 16:09:13

Solution

一道披着黑皮的蓝... ------------ sb组合数学,但我不会qwq ------------ 设f[i,j]为i对情侣,恰有j对在一起的方案数。 ------------ 显然,对于这j对在一起的,我们要先从i排里找出j排,有C(i,j)种方法;再把这些人排个顺序坐,有P(i,j)种方法,考虑左右交换:有2^j种方案。 ------------ 那么问题来了,对于这i-j对不坐在一起的怎么办?我们可以递推求解,设g[k]为k对情侣都不坐在一起的方案数。那么我们分类讨论: ------------ 1、先选择一对~~基佬~~ ------------ 显然,方案数为C(k,2)*2,乘2还是因为可以交换。化简可得k*(k-1) ------------ 2、先选择一对妹子 ------------ 显然同上。 3、选择一男一女,但不是情侣 ------------ 男的k个里总得选一个,女的就有一个不能选,左右交换也是可以的,所以是2*k*(k-1) 选完后,考虑他们的配偶(~~总不能晾着不管~~ ------------ 1、坐在一起,那么可以在k-1排里选一排,左右顺序可变,问题规模减少2; 2、不坐在一起,问题规模减少一。 乘上前面的,即可得: g[k]=4k(k-1)(g[k-1]+2(k-1)g[k-2]) ------------ 总方案数f[n,k]=C(n,k)*P(n,k)*2^k*g[k]。预处理阶乘逆元2的幂以及g数组,就可以O(1)回答啦~ ------------ 附AC代码(压行什么的,才没有呢 ``` #include<bits/stdc++.h> const int M=998244353,N=5000005; long long n,k,t,fac[N]={1},rev[N],g[N]={1,0},p[N]={1}; long long power(long long a,long long b){ long long res=1; while(b){ if(b&1)res=res*a%M; b>>=1; a=a*a%M;} return res;} int main(){ for(int i=1;i<=N;++i)fac[i]=fac[i-1]*i%M; rev[N]=power(fac[N],M-2); for(int i=N;i;--i )rev[i-1]=rev[i]*i%M; for(int i=2;i<=N;++i)g[i]=(g[i-1]+g[i-2]*2*(i-1))%M*4*i%M*(i-1)%M; for(int i=1;i<=N;++i)p[i]=p[i-1]*2%M; scanf("%lld",&t); while(t--){ scanf("%lld%lld",&n,&k); printf("%lld\n",fac[n]*rev[n-k]%M*fac[n]%M*rev[k]%M*rev[n-k]%M*p[k]%M*g[n-k]%M);} return 0;} ```