憋了一天,终于把这题做出来了。

题目大意:
给一个长度为n的序列,现在可以从中移除m个元素得到一个新序列,问一共可以得到多少个互不相同的新序列。
n<=10^5,m<=10
思路:
dp还是比较容易想到的。
令dp[i][j]表示前i个元素移除了j个以后的方案数。
那么显然第i个元素可选可不选,我们可以得到转移方程:
dp[i][j]=dp[i-1][j]+dp[i-1][j-1]。
但是这样会出现重复,举个栗子:
2 4 1 2 2 1
如果移除3个数字,我们移除[3,5]的数字和移除[4,6]的数字得到的结果是一样的。
其实就是如果有两个数字相同,那么中间的数字全部被移除的时候(如果可以被全部移除)会出现重复。

发现m<=10,即我们最多移除的数字只有10个。
那么我们枚举dpi][j]的时候,往前找第一个与a[i]相同的数字a[k],然后中间[k+1,i-1]的数字全部删除时出现重复,此时k之前的数字随便选剩下的j-(i-k),也就是dp[k-1][j-(i-k)]种方案数,我们删除这些方案数一次就可以了。

注意:只要往前找一个减去就可以了,我一开始以为在m个范围里面如果多个a[k]与a[i]相同都要减。但是其实在之前已经把更加前面的a[k]情况删除过了。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1000000007;
ll dp[100040][20];
int n,m,k,s[100050];
int main()
{
    while(~scanf("%d%d%d",&n,&m,&k)){
        for(int i=1;i<=n;i++){
            cin>>s[i];
        }
        //memset(dp,0,sizeof(dp));
        for(int i=0;i<=n;i++)dp[i][0]=dp[i][i>10?10:i]=1;
        for(int i=2;i<=n;i++){
            for(int j=1;j<=min(i-1,m);j++){
                dp[i][j]=dp[i-1][j];
              //  if(j==i-1)dp[i][j]++;
                dp[i][j]+=dp[i-1][j-1];
                dp[i][j]%=mod;
                for(int l=1;l<=j;l++){
                    if(s[i]==s[i-l]){
                        dp[i][j]=(dp[i][j]-dp[i-l-1][j-l]+mod)%mod;
                        break;
                    }
                }
                dp[i][j]%=mod;
            }
        }
        cout<<dp[n][m]<<endl;
    }

    return 0;
}