[Luogu4921]情侶?給我燒了![錯位排列]
阿新 • • 發佈:2018-10-18
+= 處理 ans ace digi 相同 () ++i 配對
題意
題意很清楚 \滑稽
分析
- 對於每一個詢問 \(k\) ,記 \(g(x)\) 表示 \(x\) 對情侶都錯開的方案總數,那麽答案可以寫成如下形式:
\[ {ans}_k= \binom{n}{k}\times A_n^k\times 2^k\times g(n-k) \] 考慮如何求 \(g(x)\) (一個錯位排列)。
考慮第一排,一共有三種情況:兩男兩女或者一男一女(不配對)。
兩男:順次選出兩男的方案數為 \(x(x-1)\) ,然後考慮他們的配偶在之後的配對情況:
如果強制不配對,那麽把她們看成一對情侶來保證之後的過程中不配對(
gay裏gay氣),即 \(g(x-1)\) 。如果強制配對,那麽在剩下的 \(x-1\) 排中選擇一排,兩人順序可以交換,轉移為 \(2(x-1)\times g(x-2)\)。
兩女:方案數顯然和兩男的情況相同。
一男一女:枚舉一男一女,可以交換順序的方案數為 \(x(x-1)\) ,轉移其實是一樣的,
所以我們得到:\(g(x)=4x(x-1)\times[g(x-1)+2(x-1)\times g(x-2)]\) 。
單次處理 \(g\) 復雜度 \(O(n)\) ,每次回答枚舉 \(k\) 復雜度 \(O(n)\) ,總時間復雜度為 \(O(n)\) 。
代碼
#include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=a;i<=b;++i) #define pb push_back typedef long long LL; inline int gi(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();} return x*f; } template<typename T>inline bool Max(T &a,T b){return a<b?a=b,1:0;} template<typename T>inline bool Min(T &a,T b){return b<a?a=b,1:0;} const int N=2004,mod=998244353; int T,n; LL fac[N],inv[N],invfac[N],bin[N],g[N]; void add(LL &a,LL b){a+=b;if(a>=mod) a-=mod;} LL Pow(LL a,LL b){ LL res=1ll; for(;b;b>>+1,a=a*a%mod) if(b&1) res=res*a%mod; return res; } LL C(int n,int m){ return fac[n]*invfac[n-m]%mod*invfac[m]%mod; } int main(){ fac[0]=invfac[0]=inv[1]=bin[0]=1; rep(i,1,N-1){ if(i^1) inv[i]=(mod-mod/i)*inv[mod%i]%mod; fac[i]=fac[i-1]*i%mod; invfac[i]=invfac[i-1]*inv[i]%mod; bin[i]=bin[i-1]*2%mod; } g[0]=1,g[1]=0; rep(n,2,1000) g[n]=4ll*n*(n-1)%mod*(g[n-1]+2*(n-1)*g[n-2])%mod; T=gi(); while(T--){ n=gi(); rep(k,0,n) printf("%lld\n",C(n,k)*C(n,k)%mod*fac[k]%mod*bin[k]%mod*g[n-k]%mod); } return 0; }
[Luogu4921]情侶?給我燒了![錯位排列]