[題解]Codeforces Round #519 - D. Mysterious Crime

【題目】ios

D. Mysterious Crime數組

【描述】ide

有m個n排列,求一共有多少個公共子段。spa

數據範圍:1<=n<=100000,1<=m<=103d

【思路】code

對於第一個排列來講,若是第k個位置開始日後L長的子段是一個公共的子段,那麼從k開始日後數1,2,...,L-1長的子段都是公共的子段;若是第k個位置開始日後L長的子段是一個公共的子段,但第k個位置開始日後L+1長的子段不是一個公共的子段,那麼位置k到位置k+L中任一位置j開始日後直到位置k+L的子段都不是公共的子段。這就意味着公共的子段被劃分紅了若干個部分,每一個部分必定有最長的一個公共子段。對於一個最長的公共子段,不妨設其長度爲L,則與它劃分在同一組內的公共子段也就是它的子段,長度爲1的有L個,長度爲2的有L-1個…… 因而這一組一共有1+2+...+L=(L+1)*L/2個公共子段。blog

用一個數組pos[x][i]=j表示數字x在第i個排列中是第j個。要判斷第k個位置的數是否還跟前面是在同一組,就須要判斷前面那一組的開始(設爲第p個位置)處的數和第k個位置處的數在m個排列中的相對位置是否都同樣,便是不是都相差k-p,作一次檢查須要O(m)。而因爲公共子段的劃分是不重合的(即沒有一個公共子段屬於一個以上的組),因而只須要從前日後掃一遍:從i開始向後擴展公共子段,當新的位置再也不屬於前一個組時,起始位置i跳到這個新的位置繼續重複以前的操做。因而總的複雜度爲O(n*m)。get

(智障的zyy在比賽的時候把上一段加粗處的地方寫錯了,直接把位置當作這個位置上的數那來算,居然還過了6組數據orz…… 由於這個智障的問題,再一次跟跑回expert失之交臂…… (年輕時候的zyy真厲害啊…… (說不定這道題作對了也回不了expert呢orz…… (閉嘴吧……string

【個人實現】it

複雜度:O(n*m)

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cstring>
 5 
 6 using namespace std;
 7 #define MaxN 100020
 8 #define MaxM 20
 9 
10 long long pos[MaxN][MaxM];
11 long long a[MaxN];
12 long long Len[MaxN];
13 int n, m;
14 bool Check(int x, int y) //true: same
15 {
16     int delta = pos[x][1] - pos[y][1];
17     for(int i = 2; i <= m; i++)
18         if(pos[x][i] - pos[y][i] != delta)
19             return false;
20     return true;
21 }
22 
23 int main()
24 {
25     int i, j;
26     int x;
27     long long Ans;
28     scanf("%d%d", &n, &m);
29     for(i = 1; i <= m; i++)
30     {
31         for(j = 1; j <= n; j++)
32         {
33             scanf("%d", &x);
34             pos[x][i] = j; //x zai i hang j lie
35             if(i == 1)
36                 a[j] = x;
37         }
38     }
39     memset(Len, 0, sizeof(Len));
40     for(i = 1; i <= n; )
41     {
42         Len[i]++;
43         for(j = i+1; j <= n; j++)
44         {
45             if(Check(a[i], a[j]))
46                 Len[i]++;
47             else
48             {
49                 //i = j;
50                 break;
51             }
52         }
53         i = j;
54     }
55     Ans = 0;
56     for(i = 1; i <= n; i++)
57         if(Len[i])
58             Ans += Len[i] * (Len[i] + 1) / 2;
59     cout << Ans << endl;
60     return 0;
61 }
View Code

【評測結果】

相關文章
相關標籤/搜索