[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\n",f(n,k));
        }
    }
    return 0;
}
posted @ 2018-12-26 08:57 nosta 阅读(...) 评论(...) 编辑 收藏