牛客网暑期ACM多校训练营(第一场) E Removal dp递推

时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld

题目描述

Bobo has a sequence of integers s 1, s 2, …, s n where 1 ≤ s i ≤ k.
Find out the number of distinct sequences modulo (10 9+7) after removing exactly m elements.

输入描述:

The input consists of several test cases and is terminated by end-of-file.
The first line of each test case contains three integers n, m and k.
The second line contains n integers s1, s2, ..., sn.

输出描述:

For each test case, print an integer which denotes the result.


输入例子:
3 2 2
1 2 1
4 2 2
1 2 1 2


输出例子:
2
4

题意 给出一个串 从中删除m个字符 问最多能产生多少种子串。

解题思路:
叉姐的题解没看懂。
用的是别人博客上的方法。
可以这么想:
首先 这是一个计数问题,那么考虑如何避免重复的问题。
通过思考得到 将字符串分为 A B C 三段,我们对B段进行删除操作,那么只要B中没有相同的字符,就不会有重复的情况。 根据这一点 可以想到一个状态定义
dp[i][j]=长度为i以数字j为结尾的方案数
但这样不好转移 我们可以再列一个状态
sum[i][j] 表示前i个字符处理完后 长度为j的子序列方案数。
这样就很好转移了。。。。。。。。。
具体转移见代码
但是这样时空复杂度都是n^2的
可以这么优化
对于空间复杂度,可以采用滚动数组优化 既从后往前更新
对于时间复杂度,由于m最多只有10 所以我们第二层循环 最多为10
这样复杂度就控制在了1e6左右。 可以接受了。

要注意的是,由于多组输入 , 直接memset整个数组会超时。 可能会超时

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#define N 2000050

using namespace std;
typedef long long LL;
const int MAX=1e5+10;
long long dp[MAX][20];
const int MOD= 1e9+7;
long long ans[MAX];
long long a[MAX];
int main(){
    int n,m,k;
    while(~scanf("%d %d %d",&n,&m,&k)){
        for(int i=1;i<=n;i++){
            ans[i]=0;
            memset(dp[i],0,sizeof dp[i]);
        }
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
        }
        ans[0]=1;
        for(int i=1;i<=n;i++){
            for(int j=i;j>=1 && j>=i-m-1;j--){
                ans[j]=(ans[j]+ans[j-1]-dp[j][a[i]])%MOD;
                dp[j][a[i]]=ans[j-1];
            }
        }
        ans[n-m]=(ans[n-m]+MOD)%MOD;
        cout<<ans[n-m]<<endl;
    }
}

猜你喜欢

转载自blog.csdn.net/lifelikes/article/details/81138624