【Codeforces301E】Yaroslav and Arrangements
阿新 • • 發佈:2019-02-13
題意:
- 給出
n,m,k ,詢問有多少個長度為n 的陣列b 滿足以下要求:
b[i]≤b[i+1](1≤i<n) 1≤b[1]≤b[n]≤m - 將
b 陣列排列後有大於等於一種小於等於k 種排列a 滿足以下要求:
|a[i]−a[i+1]|=1(1≤i<n) |a[n]−a[1]|=1 a[1]=minni=1a[i]
n,m,k≤100
題解:
- 首先我們可以假設
a[1]=1 ,最後將答案乘上m−i+1 即可。 - 不妨破環成鏈,設
a[n+1]=a[1] 。 - 設
dp[i][j][k][l] 表示目前最大數為i ,已經有j 個數,有k 個空必須加數,滿足的排列數已有l 種的方案數。 - 轉移比較顯然:
- 列舉
i 的個數t 。 dp[i][j][k][l]−>dp[i+1][j+t][t−k][l∗Ck−1t−1] - 注意,只有一個數顯然是不可以的(因為我們開始已經讓
n 加一了)。
程式碼:
#include <bits/stdc++.h>
#define ll long long
#define mod 1000000007
#define N 109
using namespace std;
int c[N][N],n,m,K,dp[2][N][N][N],Ans;
void add(int &x,int y)
{
x=(x+y>=mod)?x+y-mod:x+y;
}
int main()
{
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n>>m>>K;
c[0][0]=1;
for (int i=1;i<=K;i++)
for (int j=0;j<=i;j++)
{
c[i][j]=(j?c[i-1][j-1]:0)+c[i-1][j];
if (c[i][j]>K) c[i][j]=K+1;
}
n++;
int now=1,last=0;
dp[now][0][1][1]=1;
for (int i=0;i<=m;i++)
{
last=now,now^=1;
if (i)
{
int tmp=0;
for (int j=2;j<=n;j++)
for (int l=1;l<=K;l++) add(tmp,dp[last][j][0][l]);
add(Ans,(ll)tmp*(m-i+1)%mod);
}
if (i==m) break;
memset(dp[now],0,sizeof(dp[now]));
for (int j=0;j<=n;j++)
for (int k=1;k<=n;k++)
for (int l=1;l<=K;l++)
if (dp[last][j][k][l])
for (int t=k;t<=n-j;t++)
if (l*c[t-1][k-1]<=K)
add(dp[now][j+t][t-k][l*c[t-1][k-1]],dp[last][j][k][l]);
}
cout<<Ans<<'\n';
return 0;
}