时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld
空间限制: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.
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;
}
}