HDU4372 Count the Buildings
阿新 • • 發佈:2020-07-27
Description
現在有一列樓,共 \(n\) 個,從前面看是 \(f\) 個,從後面看有 \(b\) 個,樓的高度是一個排列
這裡能看見得滿足上升子序列
求有多少種的排列滿足條件
\(n,f,b\le 2000\)
Solution
一定能看到最高的那個樓,所以該正反的序列就都以高度為 \(n\) 的為結尾
然後就是在剩下的 \(n-1\) 個裡面選 \(b-1\) 個構成下降序列扔後面,選 \(f-1\) 個構成上升序列扔前面
所以這 \(n\) 個數被分組了,而且就直接是圓排列……
再想上這幾個組再組合一下可以分成前面的 \(f-1\) 個和後面的 \(b-1\) 個,所以
\[ans=\binom {(b-1)+(f-1)} {f-1}\times S(n-1,(b-1)+(f-1)) \]
\(O(n^2)\) 預處理斯特林數,和組合數(這裡考慮到爆空間,我用了線性的……)
Code
#include<bits/stdc++.h> using namespace std; namespace yspm{ inline int read() { int res=0,f=1; char k; while(!isdigit(k=getchar())) if(k=='-') f=-1; while(isdigit(k)) res=res*10+k-'0',k=getchar(); return res*f; } const int mod=1e9+7; const int N=4010; int n,f,b,s[N][N],inv[N],fac[N]; inline int C(int n,int m){return 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod;} inline void work() { n=read(); f=read(); b=read(); printf("%lld\n",1ll*s[n-1][b+f-2]*C(b+f-2,f-1)%mod); return ; } inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;} signed main() { s[1][1]=1; inv[1]=inv[0]=fac[0]=1; for(int i=1;i<N;++i) fac[i]=1ll*fac[i-1]*i%mod; for(int i=2;i<N;++i) inv[i]=mod-1ll*mod/i*inv[mod%i]%mod; for(int i=1;i<N;++i) inv[i]=1ll*inv[i-1]*inv[i]%mod; for(int i=2;i<N;++i) for(int j=1;j<=i;++j) s[i][j]=add(s[i-1][j-1],1ll*(i-1)*s[i-1][j]%mod); int T=read(); while(T--) work(); return 0; } } signed main(){return yspm::main();}