【MIPT Workshop Open 1 K】Blocks 題解
阿新 • • 發佈:2018-11-27
題目大意
有
個柱子,高度構成
~
的排列。現在你要把他們排在一行,使得從左邊看能看到恰好
根柱子,從右邊看能看到恰好
根柱子。求方案數。共
組資料。
題解
可以很自然地想到 dp,從大到小放柱子,那麼放在邊上的就可以被看到,放到中間的就看不到。
這裡要注意的是不要把左邊和右邊分開考慮,就是說不要什麼分別算左邊和右邊然後合併,或者 dp 式子裡設左邊和右邊分別看到了多少柱子。我不會告訴你我就是這樣被卡了 2h 多。這樣子始終會有一個
的時間。
但是可以發現一個新的柱子放兩邊其實是本質相同的!
所以設 f[i][j] 表示從大到小放了
個柱子(方便起見,去掉最高的那個),兩邊可見的共有
個,的方案數。新加進來一個柱子要麼放兩邊使
加一,要麼放中間。
最後詢問的時候乘個
就好啦。
這樣就是 的了。
程式碼
#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long LL;
const int maxn=5e4+5, maxp=205;
const LL mo=1e9+7;
int n,p,q;
LL f[maxn][maxp],C[maxp][maxp];
int m;
int main()
{
n=50000, p=200;
f[0][0]=1;
fo(i,1,n-1)
fo(j,1,min(p,i)) f[i][j]=(f[i-1][j-1]+f[i-1][j]*(i-1))%mo;
fo(i,0,p)
{
C[i][0]=1;
fo(j,1,i) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mo;
}
scanf("%d",&m);
while (m--)
{
scanf("%d %d %d",&n,&p,&q);
LL ans=f[n-1][p+q-2]*C[p+q-2][p-1]%mo;
printf("%lld\n",ans);
}
}