链接:https://www.nowcoder.com/acm/contest/139/E
来源:牛客网
题目描述
Bobo has a sequence of integers s1, s2, ..., sn where 1 ≤ si ≤ k.
Find out the number of distinct sequences modulo (109+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.
示例1
输入
复制
3 2 2 1 2 1 4 2 2 1 2 1 2
输出
复制
2 4
备注:
* 1 ≤ n ≤ 1e5 * 1 ≤ m ≤ min{n - 1, 10} * 1 ≤ k ≤ 10 * 1 ≤ si ≤ k * The sum of n does not exceed 1e6.
题目大意:给你一个n长的序列,去掉m个数字后有多少个不同的序列
参考了https://www.nowcoder.com/discuss/87183?type=101&order=0&pos=22&page=1
实际上是求有多少个不同的长度为n-m的子序列
设dp[i][j]是长度为i,末尾数字为j的子序列个数,设sum[i]为长度为i的子序列个数,那么有
for(int i=1;i<=n;i++)
{
for(int j=i;j>=1;j--)
{
sum[j]+=sum[j-1]-dp[j][num[i]];
}
}
为什么要减去dp[j][num[i]]呢,因为在前面的状态转移中,长度为j的末尾数字为num[i]的子序列可能被计算过了,所以要减去
直接这样O(n^2)肯定是会超时的,考虑优化的办法:我们只需要倒数前m个数,所以可将循环改为j>=i-m-1,这样可把复杂度降到O(nm)
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1e5+7;
const int mod=1e9+7;
int n,m,k;
int num[maxn];
int dp[maxn][20];
int sum[maxn];
int main()
{
while(~scanf("%d%d%d",&n,&m,&k))
{
memset(dp,0,sizeof(dp));
memset(sum,0,sizeof(sum));
for(int i=1;i<=n;i++)
{
scanf("%d",&num[i]);
}
sum[0]=1;
for(int i=1;i<=n;i++)
{
for(int j=i;j>=1;j--)
{
sum[j]+=sum[j-1]-dp[j][num[i]];
}
}
for(int i=1;i<=n;i++)
{
for(int j=i;j>=1&&j>=i-m-1;j--)
{
sum[j]+=(sum[j-1]-dp[j][num[i]])%mod;
sum[j]%=mod;
dp[j][num[i]]=sum[j-1];
}
}
int ans=sum[n-m]%mod;
ans+=mod;
ans%=mod;
cout<<ans<<endl;
}
return 0;
}