https://www.nowcoder.com/acm/contest/139/E
解法一:
dp[i][j]
d
p
[
i
]
[
j
]
表示加入第i个数字后,总共删掉
j
j
个数字时,有多少种不同的序列。
不考虑重复的dp方程为:
那么在这里减去重复的数据就是正确的答案。
例如
acdijkc
a
c
d
i
j
k
c
其中重复的两个状态就是
ac
a
c
,其实可以判断出,重复的情况必定在存在相同字母时出现。我们可以保存一下每一个字母之前字母出现的位置,当中间的字母全被删掉时,两者就会重复。即
dp[i][j]−=dp[pre[i]−1][j−(i−pre[i])];
d
p
[
i
]
[
j
]
−
=
d
p
[
p
r
e
[
i
]
−
1
]
[
j
−
(
i
−
p
r
e
[
i
]
)
]
;
为什么多减了一位呢?请观察
dp[i][j]
d
p
[
i
]
[
j
]
.
#include<bits/stdc++.h>
using namespace std;
#define ll long long int
const int maxn=1e5+25;
const int p=1e9+7;
ll dp[maxn][15];
int a[maxn];
int pre[maxn];
int vis[15];
int main()
{
int n,m,k;
while(~scanf("%d %d %d",&n,&m,&k)){
memset(vis,0,sizeof vis);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=0;i<=n;i++){pre[i]=0;}
for(int i=0;i<=n;i++){
for(int j=0;j<=m;j++){
dp[i][j]=0;
}
}
for(int i=1;i<=n;i++){
if(!vis[a[i]]){
vis[a[i]]=i;
}
else{
pre[i]=vis[a[i]];
vis[a[i]]=i;
}
}
for(int i=0;i<=n;i++) dp[i][0]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
(dp[i][j]=dp[i-1][j]+dp[i-1][j-1])%=p;
if(pre[i]){
if(i-pre[i]<=j){
dp[i][j]-=dp[pre[i]-1][j-(i-pre[i])];
(dp[i][j]+=p)%=p;
}
}
}
}
printf("%lld\n",dp[n][m]);
}
return 0;
}