这个题是将长度为n的序列里面删去m个元素,问你有多少种剩下来的序列情况。
很容易联想到dp
首先如果两两都不同,那么直接01背包
dp[i][j]=dp[i-1][j-1]+dp[i-1][j];
但是题目里面有可能会出现重复元素,这个时候就要去剪掉一些方案数了。
我们记录下来每一个数前面最近的值相同的元素的pos位置,从前到后扫一遍就可以得到。
然后我们计数的时候,要加一个判断。如果dp[i][j]此时的pre[i]=k&&j>=(i-k),那么就要减去一部分
dp[i][j]=(dp[i][j]-dp[k-1][j-(i-k)]+mo)%mo;
具体见代码吧
#include<bits/stdc++.h>
using namespace std;
int dp[100010][100],a[100010],last[100010],pre[100010];
int main()
{ int n,m,k;
while(cin>>n>>m>>k)
{
memset(last,0,sizeof(last));
memset(pre,0,sizeof(pre));
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;++i)
{
pre[i]=last[a[i]];
last[a[i]]=i; //更新当前
}
for(int i=0;i<=n;i++) dp[i][0]=dp[i][i]=1; //初始化
for(int i=1;i<=n;i++)
{
for(int j=1;j<=min(m,i);j++){
dp[i][j]=(dp[i-1][j-1]+dp[i-1][j])%(1000000007);
if(pre[i]!=0&&j>=(i-pre[i])){
int k=pre[i];
dp[i][j]=(dp[i][j]-dp[k-1][j-(i-k)]+1000000007)%1000000007;
}
}
}
cout<<dp[n][m]<<endl;
}
return 0;
}


京公网安备 11010502036488号