• [P4921] 情侣?给我烧了!


    回顾一下错排公式

    错排问题:
    设n位错排数为D[n]。考虑元素1的位置,设置为k(有n-1中 );在考虑元素k的位置,
    若为1,则转换为n-2位的错排;否则,视元素k为元素1(不能放在位置1),转换为n-1位的错排。
    故 D[n]=(n-1)(D[n-1]+D[n-2]) D[1]=0 D[2]=1
    也有公式D[n]=n!/e (e=1-1/1!+1/2!-1/3!+……+(-1)^n*1/n!)

    设g(x)为x对情侣都在x排里都错开的方案数。
    对于询问的k,其答案=C(n,k)A(n,k)pow(2,k)*g(n-k)

    式子从左到右依次表示:
    1)在n排中选出k排
    2)每对情侣中占某一排排
    3)情侣双方的位置互调
    4)剩下n-k对情侣都要错开。

    然后考虑g(x)的算法。

    这是就要联想到错排序列的构造方法。
    考虑第一排的情况:
    1)俩男(x(x-1)种),考虑他们对应的俩女
    a)这俩女在同一排((x-1)
    2种方案),此时转化为g(x-2)。
    b)这俩女不在同一排, 就把她们当做一对情侣,转化为g(x-1)
    2)俩女,与俩男同
    3)左男右女,仔细想想是与俩男还是一样的。
    4)左女右男,仔细想想是与俩男还还是一样的。

    故转移为g(x)=(1+1+1+1)(x(x-1)((x-1)2*g(x-2)+g(x-1)))=4x(x-1)(2(x-1)g(x-2)+g(x-1))
    显然g(1)=0, g(2)=8 //于是g(0)=1...

    时间复杂图 O(Tn)

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=1e3+7;
    const int P=998244353;
    
    int fac[N]={1};
    int inv[N]={0,1};
    int fiv[N]={1};
    int g[N]={1};
    int b[N]={1};
    
    inline int C(int x,int y) {
    	return 1LL*fac[x]*fiv[y]%P*fiv[x-y]%P;
    }
    inline int A(int x,int y) {
    	return 1LL*fac[x]*fiv[x-y]%P;
    }
    inline int f(int n,int k) {
    	return 1LL*C(n,k)%P*A(n,k)%P*b[k]%P*g[n-k]%P;
    }
    
    int main() {
    	for(int i=1; i<N; ++i) fac[i]=1LL*fac[i-1]*i%P;
    	for(int i=2; i<N; ++i) inv[i]=1LL*(P-P/i)*inv[P%i]%P;
    	for(int i=1; i<N; ++i) fiv[i]=1LL*inv[i]*fiv[i-1]%P;
    	for(int i=2; i<N; ++i) g[i]=4LL*i*(i-1)%P*(2LL*(i-1)*g[i-2]%P+g[i-1])%P;
    	for(int i=1; i<N; ++i) b[i]=b[i-1]*2LL%P;
    	int T,n;
    	scanf("%d",&T);
    	while(T--) {
    		scanf("%d",&n);
    		for(int k=0; k<=n; ++k) {
    			printf("%d
    ",f(n,k));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    C语言学习之指针
    IT人和普洱茶
    茶如人生 你是什么茶?
    普洱茶的冲泡技巧
    普洱茶保健功效
    廖雪峰Python总结3
    廖雪峰Python总结2
    Linux之软件包安装管理
    Linux常用命令6 关机重启命令
    Linux之Vim编辑器
  • 原文地址:https://www.cnblogs.com/nosta/p/10177343.html
Copyright © 2020-2023  润新知