牛客网多校训练第一场 E - Removal(线性DP + 重复处理)

链接:

https://www.nowcoder.com/acm/contest/139/E

题意:

给出一个n(1≤n≤1e5)个整数(范围是1至10)的序列,
求从中移除m(1≤m≤min(n-1,10))个整数后不同序列的数量模(1e9+7)。

分析:

设d[i][t]表示当前匹配到了第i个数字,总共删了t个数字时的不同序列的数量。
先不考虑序列重复的情况,
则d[i][t] = d[i-1][t](不删第i个数字)+ d[i-1][t-1](删第i个数字)。
现在考虑减去重复的序列。
设有序列abcdec(以字符串为例),可以发现,s[3]=s[6],当i=6,t=3时,
删除cde与删除dec得到的序列是一样的,都是abc,即匹配到s[6]时产生了重复。
这时减去删除cde的方案数(与其前面序列ab相应的方案数相同)即可。
即d[6][3]减去d[2][0](表示从前面的2个元素中删除0个元素,最后再删除cde的方案数)。

代码:

 1 import java.io.*;
 2 import java.util.*;
 3 import static java.util.Arrays.*;
 4 
 5 public class Main {
 6     Scanner cin = new Scanner(new BufferedInputStream(System.in));
 7     final int UP = (int)1e5 + 5;
 8     final long MOD = (long)1e9 + 7;
 9     int last[] = new int[10+5]; // last[i]:数字i之前出现的最后位置
10     long d[][] = new long[UP][10+5];
11     
12     void MAIN() {
13         for(int i = 0; i < 10+5; i++) d[i][i] = 1;
14         for(int i = 0; i < UP; i++) d[i][0] = 1;
15         while(cin.hasNext()) {
16             int n = cin.nextInt();
17             int m = cin.nextInt();
18             cin.nextInt();
19             fill(last, 0);
20             for(int v, i = 1; i <= n; i++) {
21                 v = cin.nextInt();
22                 for(int t = 1; t <= m; t++) {
23                     d[i][t] = (d[i-1][t] + d[i-1][t-1]) % MOD;
24                     if(i - last[v] > t || last[v] == 0) continue; // 当i-last[v]<=t时才会出现重复
25                     d[i][t] = (d[i][t] - d[last[v]-1][t-(i-last[v])] + MOD) % MOD;
26                 }
27                 last[v] = i;
28             }
29             System.out.println(d[n][m]);
30         }
31     }
32     
33     public static void main(String args[]) { new Main().MAIN(); }
34 }

猜你喜欢

转载自www.cnblogs.com/hkxy125/p/9363831.html