给出一个n个数的序列,要求求出删除m个数字后能够产生的序列个数模1e9+7的结果。
传送门
显然是一个dp,考虑定义dp[i][j]为前i项删除j位后的种类数,显然j应当小于i
求转移方程为:dp[i][j]=dp[i-1][j-1]+dp[i-1][j],可以理解为对于第i个数字,有选或者不选两种,选的话dp[i][j]是前i-1个删j个,否则的话是前i-1个删j-1个。
但是会有许多重复的序列,考虑如何去重,考虑到只会在删除当前第i个以及前面的与第i个相同的之间的所有序列时,会产生重复,则减去删除这些后剩下的那些最多产生的种类数即可。代码如下;
#include<bits/stdc++.h>
using namespace std;
const int mod=1000000007;
#define maxn 123456
int pre[maxn],head[15];
int n,m,k,dp[maxn][15],a[maxn];
int main()
{
while(~scanf("%d%d%d",&n,&m,&k))
{
memset(dp,0,sizeof(dp));
memset(pre,0,sizeof(pre));
memset(head,0,sizeof(head));
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
pre[i]=head[a[i]];
head[a[i]]=i;
}
dp[0][0]=1;
for(int i=1; i<=n; i++)
{
dp[i][0]=1;
for(int j=1; j<=m&&j<=i; j++)
{
dp[i][j]=dp[i-1][j]+dp[i-1][j-1];
if(pre[i]&&j>=i-pre[i])
dp[i][j]-=dp[pre[i]-1][j-(i-pre[i])];
dp[i][j]%=mod;
dp[i][j]+=mod;
dp[i][j]%=mod;
}
}
printf("%d\n",dp[n][m]);
}
return 0;
}