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

链接: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;
}

猜你喜欢

转载自blog.csdn.net/qq_37943488/article/details/81292649