Atcoder Grand Contest 024E Sequence Growing Hard

题目在这里呀!
啊啊啊准备了一个月期末考的我终于飘回来啦~~
真可谓在学OI的时候忘不了文化课,然后在学文化课的时候又想念编程啦qwq

那那那开始我的七月第一篇题解?
(我七月想写很多很多题解的w)


题意

考虑 N +1 个数组 {A0,A1,…,AN}。
其中 Ai 的长度是 i,Ai 内的所有数字都在 1 到 K 之间。 Ai−1 是 Ai 的子序列,即 Ai 删一个数字可以得到 Ai−1。 Ai 的字典序大于 Ai−1。
输入 N,K,M 问序列个数模 M。

题解

好像有两种方法?
反倒我还没理解那个好理解的方法,以后补全吧
很容易想到dp吧。
那么那么
考虑每次从前面那个状态插入一个数,那么插入位置右边的那个数要严格小于插入的数。
所以我们去想想状态
f i , j , p 表示当前长度为i,取到数字j,有p个位置可插的方案数。
那么考虑转移,
一种情况,不插在这个位置,那么 f i , j , p 1 += f i , j , p
还有就是插在这个位置,那么 f i + 1 , j , p += f i , j , p
或者这个数字不插了, f i , j + 1 , i += f i , j , p 第三维为i是因为j加1了所以所有数字都比它小。
答案就是 f n , k + 1 , n

然后…就好了?代填坑(另一种方法)

//Suplex
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
int n,k,m;
long long f[333][333][333];

int main()
{
    scanf("%d%d%d",&n,&k,&m);
    f[0][1][0]=1;
    for(int i=0;i<=n;i++)
        for(int j=1;j<=k;j++)
            for(int p=i;p>=0;p--){
                if(p) (f[i][j][p-1]+=f[i][j][p]) %= m;
                else (f[i][j+1][i]+=f[i][j][p]) %= m;
                (f[i+1][j][p]+=f[i][j][p]*(p+1)) %= m;
            }
    printf("%lld\n",f[n][k+1][n]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/leo_nasir/article/details/80917032