题意:一个长为n(1e5)的序列,序列中每个数<=k,现在删除m(<=10)个位置的数 。问有多少种不同的序列
思路:
DP。设dp[i][j]为到第i个位置,删除j个有多少个不同的序列. 接下来就去找后面跟1~k是不是存在即可。
#include<bits/stdc++.h>
#define PI acos(-1.0)
#define pb push_back
#define F first
#define S second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=1e5+5;
const int MOD=1e9+7;
template <class T>
bool sf(T &ret){ //Faster Input
char c; int sgn; T bit=0.1;
if(c=getchar(),c==EOF) return 0;
while(c!='-'&&c!='.'&&(c<'0'||c>'9')) c=getchar();
sgn=(c=='-')?-1:1;
ret=(c=='-')?0:(c-'0');
while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
if(c==' '||c=='\n'){ ret*=sgn; return 1; }
while(c=getchar(),c>='0'&&c<='9') ret+=(c-'0')*bit,bit/=10;
ret*=sgn;
return 1;
}
int a[N];
int nt[N][20];
ll dp[N][20];
int pos[20];
int cnt[11];
int n,m,k;
void init(){
memset(pos,0,sizeof pos);
memset(cnt,0,sizeof cnt);
for(int i = 0; i <= n; i++)
for(int j = 0; j <= 10; j++)
dp[i][j] = nt[i][j] = 0;
}
int main(void){
while((scanf("%d%d%d",&n,&m,&k))==3){
init();
for(int i=1;i<=n;i++) sf(a[i]);
// for(int i=1;i<=k;i++)
// if(cnt[i]) dp[1][0]++;
for(int i=n;i>=0;i--){
for(int j=1;j<=k;j++){
nt[i][j]=pos[j];
}
pos[a[i]]=i;
}
// for(int j=1;j<=k;j++) cout <<"~"<< nt[1][j]<<endl;
dp[0][0]=1;
for(int i=0;i<=n;i++){
for(int j=0;j<=m;j++){
for(int num=1;num<=k;num++){
if(nt[i][num]-i-1+j>m || !nt[i][num]) continue;
dp[nt[i][num]][nt[i][num]-i-1+j]+=dp[i][j];
dp[nt[i][num]][nt[i][num]-i-1+j]%=MOD;
// cout <<i <<" "<<j<<" "<<k<<endl;
}
}
}
// cout <<"debug"<<endl;
ll ans=0;
for(int i=n;i>=1;i--){
if(m-(n-i)>=0) ans=(ans+dp[i][m-(n-i)])%MOD;
}
ans%=MOD;
printf("%lld\n",ans);
}
return 0;
}