zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    String类源码解析之理解indexOf函数--转载
    SQL优化--转载
    通过cmd/批处理 开启关闭windows中的mysql数据库
    windows查看连接过wifi的密码
    Java Annotation认知(包括框架图、详细介绍、示例说明)--转载
    springboot加载配置文件的优先级
    SpringBoot项目创建的三种方式
    雷总小米十周年演讲---国外友人评价第一次看到MIUI系统
    装饰器模式
    嵌套的setTimeout
  • 原文地址:https://www.cnblogs.com/Itst/p/10342179.html
Copyright © 2011-2022 走看看