【题解】P4859 [MtOI2018] 情侣?给我烧了! 题解

[MtOI2018] 情侣?给我烧了!\({}^\texttt{P4859}\)题解

定义:\(f_i\) 表示有多少种不同的就坐方案满足至少\(i\) 对情侣是和睦的;\(g_i\) 表示有多少种不同的就坐方案满足恰好\(i\) 对情侣是和睦的。

\(f_i=\displaystyle{{n\choose i}{n\choose i}}i!2^i(2n-2i)!\)\(f_i =\displaystyle{\sum{j\choose i}g_j}\)

所以

\[\begin{align*} g_i&=\displaystyle{\sum{j\choose i}(-1)^{i-j}f_j}\\ &=\displaystyle{\sum\frac{j!}{i!(j-i)!}(-1)^{j-i}f_j}\\ &=\displaystyle{\frac1{i!}\sum\frac{(-1)^{j-i}}{(j-i)!}j!f_j}&(i\le j \le n)\\ \end{align*} \]

定义多项式 \(A_i = i!f_i\)\(B_i=\displaystyle{\frac{(-1)^{n-i}}{(n-i)!}}\)\(C=A\times B\),使用 \(\texttt{NTT}\)

\(g_i=\displaystyle{\frac1{i!}}C_{i+n}\)

Code

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
namespace gtx{
//	Fast IO
    void read(int &x){
        x = 0;int h = 1;char tmp;
        do{tmp=getchar();if(tmp=='-')h*=-1;}while(!isdigit(tmp));
        while(isdigit(tmp)) x*=10,x+=tmp-'0',tmp=getchar();
        x*=h;
    }
    void read(char &x){do{x=getchar();}while(x==' '||x=='\n'||x=='\r');}
    void write(char x){putchar(x);}
    void write(int x){
        if(x<0) putchar('-'),x=-x;int st[200]={0},tot=0;
        do st[++tot]=x%10,x/=10; while(x);
        while(tot){putchar(st[tot--]+'0');}
    }
    void write(int x,char y){write(x);write(y);}
#ifndef int
    void read(long long &x){
        x = 0;int h = 1;char tmp;
        do{tmp=getchar();if(tmp=='-')h*=-1;}while(!isdigit(tmp));
        while(isdigit(tmp)) x*=10,x+=tmp-'0',tmp=getchar();
        x*=h;
    }
    void write(long long x){
        if(x<0) putchar('-'),x=-x;int st[200]={0},tot=0;
        do st[++tot]=x%10,x/=10; while(x);
        while(tot){putchar(st[tot--]+'0');}
    }
    void write(long long x,char y){write(x);write(y);}
#endif
    const int MAXN = 1000*7+10;
    const int MOD = 998244353;
    const int g = 3;
    const int gi = 332748118;
	int n,m;
    int qpow(int x,int y){
		if(y<0) return qpow(qpow(x,-y),MOD-2);
        long long ans = 1;
        long long now = x;
        while(y){
            if(y&1) ans*=now,ans%=MOD;
            now*=now;now%=MOD;
			y>>=1;
        }
        return ans;
    }
    int inv(int x){
        return qpow(x,MOD-2);
    }
    int rev[MAXN],len;
    inline void NTT(int *A,int multi){
        for(int i = 0;i<len;i++){
            if(i>rev[i]) swap(A[i],A[rev[i]]);
        }
        for(int mid = 1;mid<len;mid<<=1){
			int tGn = 1;
			int ttimes = qpow(qpow(g,multi),(MOD-1)/(2*mid));
            for(int mergelen = 0;mergelen<len;mergelen+=(mid<<1)){
				int Gn = tGn;
				int times = ttimes;
                for(int k = mergelen;k<mergelen+mid;k++){
                    A[k] = (A[k]+(A[k+mid]*Gn)%MOD)%MOD;
                    A[k+mid] = ((A[k]-2*A[k+mid]%MOD*(Gn)%MOD)%MOD+MOD)%MOD;
					Gn *= times;Gn %= MOD;
                }
            }
        }
    }
    int A[MAXN],B[MAXN];
    int frac[MAXN],invfrac[MAXN];
    int C(int n,int m){
        return frac[n]*invfrac[m]%MOD*invfrac[n-m]%MOD;
    }
    int f(int i){
        return C(n,i)*C(n,i)%MOD*frac[(2*n-2*i)]%MOD*qpow(2,i)%MOD*frac[i]%MOD;
    }
    signed main(){
        read(n);
        frac[0] = invfrac[0] = 1;
        for(int i = 1;i<=2*n;i++){
            frac[i] = frac[i-1]*i%MOD;
            invfrac[i] = inv(frac[i]);
        }
        for(int i = 0;i<=n;i++){
            A[i] = frac[i]*f(i)%MOD;
            B[i] = ((n+i)&1?-1:1)*invfrac[n-i]%MOD;
        }
        len = 1;
        while(len<=2*n+2) len<<=1;
        for(int i = n+1;i<len;i++) A[i] = 0,B[i] = 0;
		for(int i = 1;i<len;i++){
			rev[i] = (rev[i>>1]>>1)+(i&1)*(len>>1);
		}
        NTT(A,1);
        NTT(B,1);
        for(int i = 0;i<len;i++) A[i] *= B[i],A[i]%=MOD;
        NTT(A,-1);
        for(int i = 0;i<=n;i++){
            write((invfrac[i]*A[i+n]%MOD*qpow(len,MOD-2)%MOD+MOD)%MOD,endl);
        }
        return 0;
    }
}
signed main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
//	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int T = 1;
	gtx::read(T);
    while(T--) gtx::main();
    return 0;
}
posted @ 2025-05-01 20:29  GuTongXing  阅读(22)  评论(0)    收藏  举报