标签:end oid freopen sign 中间 char ini 阶乘 预处理
第一眼看着就像容斥,但是容斥不怎么好做……
第二眼想到错排,结果错排公式糊上去错了……
不难考虑到可以先选\(K\)对情侣坐在一起,剩下\(N-K\)对错排
选\(K\)对情侣坐在一起的方案数是:
选情侣的方案数\(C_N^K \times\)选椅子的方案数\(C_N^K\times\)情侣坐的椅子可以任意排列\(K!\times\)情侣之间可以互换位置\(2^K\)=\((C_N^K)^2K!2^K\)
然后考虑这个错排
实际上直接糊错排公式是很难对的,至少我不会直接用错排公式搞出来……
设\(f_i\)表示\(i\)对情侣错排的方案数
转移时枚举两个不是情侣的人,有\(2i \times (2i-2)\)种方案
然后考虑TA们的配偶:
①两个配偶坐在了一起,$f_i \leftarrow 2i \times (2i - 2) \times (i-1) \times 2 \times f_{i-2} $,中间的\(2\)是这两个配偶可以交换位置
②没有坐在一起,就相当于一个规模为\(i-1\)的错排,\(f_i \leftarrow 2i \times (2i-2) \times f_{i-1}\)
预处理阶乘、\(2\)的次幂就可以\(O(1)\)回答询问。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<vector>
#include<cmath>
//This code is written by Itst
using namespace std;
inline int read(){
int a = 0;
char c = getchar();
bool f = 0;
while(!isdigit(c) && c != EOF){
if(c == ‘-‘)
f = 1;
c = getchar();
}
if(c == EOF)
exit(0);
while(isdigit(c)){
a = a * 10 + c - 48;
c = getchar();
}
return f ? -a : a;
}
#define int long long
const int MOD = 998244353 , MAXN = 5e6 + 9;
int shuf[MAXN] , jc[MAXN] , inv[MAXN] , pow2[MAXN];
inline int poww(int a , int b){
int times = 1;
while(b){
if(b & 1)
times = times * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return times;
}
void init(){
jc[0] = pow2[0] = 1;
for(int i = 1 ; i <= 5e6 ; ++i)
jc[i] = jc[i - 1] * i % MOD;
inv[5000000] = poww(jc[5000000] , MOD - 2);
for(int i = 5e6 - 1 ; i >= 0 ; --i)
inv[i] = inv[i + 1] * (i + 1) % MOD;
for(int i = 1 ; i <= 5e6 ; ++i)
pow2[i] = pow2[i - 1] * 2 % MOD;
shuf[0] = 1;
shuf[1] = 0;
for(int i = 2 ; i <= 5e6 ; ++i)
shuf[i] = (shuf[i - 1] + 2 * (i - 1) * shuf[i - 2]) % MOD * 2 * i % MOD * (2 * i - 2) % MOD;
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
//freopen("out","w",stdout);
#endif
init();
for(int T = read() ; T ; --T){
int N = read() , Q = read();
printf("%lld\n" , jc[N] * inv[N - Q] % MOD * jc[N] % MOD * inv[Q] % MOD * inv[N - Q] % MOD * pow2[Q] % MOD * shuf[N - Q] % MOD);
}
return 0;
}
标签:end oid freopen sign 中间 char ini 阶乘 预处理
原文地址:https://www.cnblogs.com/Itst/p/10342179.html