Loading [MathJax]/jax/output/HTML-CSS/jax.js

Codeforces301E 题解

Codeforces301E 题解

题意:

  • 给出 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;
}

C++

 

点赞 2

No Comments

Add your comment

或许此刻需要“推力”来成长。