CF1043D Mysterious Crime

思路:

参考了http://codeforces.com/blog/entry/62797,把第一个序列重标号成1,2,3,...,n,在剩下的序列中寻找形如x, x + 1, x + 2, ...的连续子段即可。

实现:

 1 #include <iostream>
 2 #include <vector>
 3 #include <cstring>
 4 using namespace std;
 5 typedef long long ll;
 6 
 7 const int INF = 0x3f3f3f3f;
 8 
 9 int a[11][100001], reach[11][100001], n, m;
10 
11 int main()
12 {
13     while (scanf("%d %d", &n, &m) != EOF)
14     {
15         memset(reach, 0, sizeof reach);
16         for (int i = 1; i <= m; i++)
17         {
18             for (int j = 1; j <= n; j++)
19                 scanf("%d", &a[i][j]);
20         }
21         vector<int> v(n + 1);
22         for (int i = 1; i <= n; i++) v[a[1][i]] = i;
23         for (int i = 2; i <= m; i++)
24         {
25             for (int j = 1; j <= n; j++)
26                 a[i][j] = v[a[i][j]];
27         }
28         for (int i = 1; i <= n; i++) reach[1][i] = n;
29         for (int i = 2; i <= m; i++)
30         {
31             int j = 1, start = 1;
32             while (j <= n)
33             {
34                 while (j + 1 <= n && a[i][j + 1] == a[i][j] + 1) j++;
35                 while (start <= j) { reach[i][a[i][start]] = a[i][j]; start++; }
36                 start = ++j;
37             }
38         }
39         ll ans = 0;
40         for (int i = 1; i <= n; i++)
41         {
42             int minn = INF;
43             for (int j = 1; j <= m; j++)
44                 if (reach[j][i])
45                     minn = min(minn, reach[j][i] - i + 1);
46             if (minn != INF) ans += minn;
47         }
48         printf("%lld
", ans);
49     }
50     return 0;
51 }
原文地址:https://www.cnblogs.com/wangyiming/p/9876648.html