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

4921

4931



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

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

不难考虑到可以先选\(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;
}

原文地址:https://www.cnblogs.com/Itst/p/10342179.html

时间: 2024-07-30 11:51:33

Luogu4921/4931 情侣?给我烧了! 组合、递推的相关文章

2825 codevs危险的组合(递推)

2825 危险的组合 时间限制: 1 s 空间限制: 64000 KB 题目等级 : 钻石 Diamond 题目描述 Description 有一些装有铀(用U表示)和铅(用L表示)的盒子,数量均足够多.要求把N个盒子放成一行,但至少有3个U放在一起,有多少种方法? 输入描述 Input Description 包含一个整数N 输出描述 Output Description 输出一个整数表示方法数. 样例输入 Sample Input 样例1:4 样例2:5 样例输出 Sample Output

Codeforces Round #526 C - The Fair Nut and String /// 组合递推

题目大意: 给定原字符序列 找出其中所有子序列满足 1.序列内字符都为a 2.若有两个以上的字符 则相邻两个字符在原序列中两者之间存在字符b 的数量 将整个字符序列用b分开 此时再得到每个b之间a的数量 即 abbgaaba 得到 v[] = { 1 0 2 1 } 此时假设到第 i-1 段 已得到在第 i-1 段内的所有方案数为 ans (长度为1.2.3.... .i-1) 则在第 i 段时 可由前一段的方案数 和 当前段数量 组合得到ans*v[ i ] (长度为2.3.4.... .i)

UVA 557 Burger 排列组合递推

When Mr. and Mrs. Clinton's twin sons Ben and Bill had their tenth birthday, the party was held at the McDonald's restaurant at South Broadway 202, New York. There were 20 kids at the party, including Ben and Bill. Ronald McDonald had made 10 hamburg

Yue Fei&#39;s Battle(组合计数递推)

//求一个直径为 k 的树有多少种形态,每个点的度不超过 3 // 非常完美的分析,学到了,就是要细细推,并且写的时候要细心 还有除法取模需要用逆元 #include <iostream> #include <stdio.h> #include <string.h> #include <math.h> #include <stdlib.h> using namespace std; #define MOD 1000000007 #define L

递推,求至少连续放置三个U的危险组合

题意 有两种方块,L和U,有至少三个连续的U称为危险组合,问有多少个危险组合 solution: 至少这个概念比较难求 ,所以转化为(1ll<<n)-安全组合 dp[n][i]表示前n个数里以i个U结尾的个数 递推方程 dp[i][0]=dp[i-1][0]+dp[i-1][1]+dp[i-1][2]; dp[i][1]=dp[i-1][0]; dp[i][2]=dp[i-1][1]; 1 #include<iostream> 2 #include<cstdio> 3

hdn2049(错排加组合) 递推超时问题!!!!

http://acm.hdu.edu.cn/showproblem.php?pid=2049 不容易系列之(4)--考新郎 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 25945    Accepted Submission(s): 9493 Problem Description 国庆期间,省城HZ刚刚举行了一场盛大的集体婚礼,为

【递推】【组合计数】UVA - 11401 - Triangle Counting

http://blog.csdn.net/highacm/article/details/8629173 题目大意:计算从1,2,3,...,n中选出3个不同的整数,使得以它们为边长可以构成三角形的个数. 思路:用一般的方法需要三重循环,时间复杂度为O(n^3),肯定超时,因此可用数学的方法对问题进行分析.设最大边长为x的三角形有c(x)个,另外两边长分别为y,z,则可得x-y<z<x:固定x枚举y,计算个数0+1+2+...+(x-2)=(x-1)(x-2)/2.上面的解包含了y=z的情况,

组合 最详细的解题报告

题目大意:已知一个数组array,长度为m,计算其中任意n个数的组合 解题思路:分析m=5,n=3时的10组组合数: 1.首先固定下标为m-1(最后一个)的数,其前面就是m-1,n-1的组合数,共6个组合: 2.其次固定下标为m-2(倒数第二个)的数,其前面就是m-2,n-2的组合数,共3个组合: 3.以此类推.一般的:m个数中n个数组合递推到“m-1个数中n-1个数的组合,m-2个数中n-1个数的组合,......, n-1个数中n-1个数的组合”,共m-n+1次递归 4.递归结束的条件是:r

[2011山东ACM省赛] Binomial Coeffcients(求组合数)

Binomial Coeffcients nid=24#time" style="padding-bottom:0px; margin:0px; padding-left:0px; padding-right:0px; color:rgb(83,113,197); text-decoration:none; padding-top:0px"> Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描写叙述 输入