1. 程式人生 > >【Codeforces301E】Yaroslav and Arrangements

【Codeforces301E】Yaroslav and Arrangements

題意:

  • 給出n,m,k,詢問有多少個長度為n的陣列b滿足以下要求:
    • b[i]b[i+1](1i<n)
    • 1b[1]b[n]m
    • b陣列排列後有大於等於一種小於等於k種排列a滿足以下要求:
      • |a[i]a[i+1]|=1(1i<n)
      • |a[n]a[1]|=1
      • a[1]=minni=1a[i]
  • n,m,k100

題解:

  • 首先我們可以假設a[1]=1,最後將答案乘上mi+1即可。
  • 不妨破環成鏈,設a[n+1]=a[1]
  • dp[i][j][k][l]表示目前最大數為i,已經有j個數,有k個空必須加數,滿足的排列數已有l種的方案數。
  • 轉移比較顯然:
  • 列舉i
    +1
    的個數t
  • dp[i][j][k][l]>dp[i+1][j+t][tk][lCk1t1]
  • 注意,只有一個數顯然是不可以的(因為我們開始已經讓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; }