牛客网暑期ACM多校训练营(第一场) E Removal 这辈子都学不会的动态规划

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/passer__/article/details/81735116

题目链接: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 ≤ 105
* 1 ≤ m ≤ min{n - 1, 10}
* 1 ≤ k ≤ 10
* 1 ≤ si ≤ k
* The sum of n does not exceed 106.

题意:给你n个数,然后删除m个问你不同的序列有多少种。

做了51nod的那个题才懂这个题如何做,就拿来补了。https://blog.csdn.net/passer__/article/details/81701761

因为对于长度不一,可以删除的数的数量也不一样,所以先预处理下同样数字出现的点,然后对于每个字母出现标记下。

对于当前i点记录和他相同的那个数字上次出现的位置。

考虑对于一个数的话要的是一个子序列,那么有三种情况。

①:前边i-1个数字已经删除了j个了 就是 dp[i-1][j]

②:前边i-1个数字已经删除了j-1个了就是dp[i-1][j-1] 再把这个删除

③:考虑某个点在可删的范围重复了

出现重复的情况 对于某一位重复的话,还需要减去重复的。

比如有1,2,3,4,5,41,2,3,4,5,4 
1,2,31,2,3所有的子序列:{1},{2},{3},{1,2},{1,3},{2,3},{1,2,3}后面再加一个4的情况{1,4},{2,4},{3,4},{1,2,4},{1,3,4},{2,3,4},{1,2,3,4}
那么这个4到底是从前一个来还是从后一个来喃?两种情况只能选一种,而且从上面阔以得出,重复的就只有这里7种 
所以转移方程是: 
④需要减去上一次出现的位置-1的那个数的序列。

dp[i][j] - dp[重复点-1][总共应该删除的j - 2个重复之间的数];

代表他们直接的数都删除掉,然后不够的从前边凑出来就好了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
int a[100005];
ll dp[100005][20];
int pre[100005];
int vis[20];
int main()
{
	int n,m,k;
	while(scanf("%d%d%d",&n,&m,&k)!=EOF)
	{
		for(int i=0;i<=k;i++)
			vis[i]=0;
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			pre[i]=vis[a[i]]; 
			vis[a[i]]=i;
		}
		for(int i=0;i<=m;i++)//m个中删除m个 
			dp[i][i]=1;
		for(int i=1;i<=n;i++)
		{
			dp[i][0]=1;//删除0个的方案数 
			for(int j=1;j<=min(i-1,m);j++)//最多删除min(i-1,m) 
			{
				dp[i][j]=(dp[i-1][j]+dp[i-1][j-1])%mod;//假如没有重复的数 
				if(pre[i] && i-pre[i]<=j) //如果不是第一次出现而且两次出现的差值在j之内 
					dp[i][j]=((dp[i][j]-dp[pre[i]-1][j-(i-pre[i])])+mod)%mod;  
			}
		} 
		printf("%lld\n",dp[n][m]);	
	}
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/passer__/article/details/81735116
今日推荐