Luogu4921/4931 情侣?给我烧了! 组合递推

Posted itst

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu4921/4931 情侣?给我烧了! 组合递推相关的知识,希望对你有一定的参考价值。

4921

4931


第一眼看着就像容斥,但是容斥不怎么好做……

第二眼想到错排,结果错排公式糊上去错了……

不难考虑到可以先选(K)对情侣坐在一起,剩下(N-K)对错排

(K)对情侣坐在一起的方案数是:

选情侣的方案数(C_N^K imes)选椅子的方案数(C_N^K imes)情侣坐的椅子可以任意排列(K! imes)情侣之间可以互换位置(2^K)=((C_N^K)^2K!2^K)

然后考虑这个错排

实际上直接糊错排公式是很难对的,至少我不会直接用错排公式搞出来……

(f_i)表示(i)对情侣错排的方案数

转移时枚举两个不是情侣的人,有(2i imes (2i-2))种方案

然后考虑TA们的配偶:

①两个配偶坐在了一起,$f_i leftarrow 2i imes (2i - 2) imes (i-1) imes 2 imes f_{i-2} $,中间的(2)是这两个配偶可以交换位置

②没有坐在一起,就相当于一个规模为(i-1)的错排,(f_i leftarrow 2i imes (2i-2) imes 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
" , 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;
}

以上是关于Luogu4921/4931 情侣?给我烧了! 组合递推的主要内容,如果未能解决你的问题,请参考以下文章

[Luogu4921]情侣?给我烧了![错位排列]

luogu P4931 情侣?给我烧了!

LG4931 情侣?给我烧了!

2019-9-11做题记录

我烧了50万RMB,换来3条社群运营经验,今天全部拿出来!

20190922