Codeforces Gym100502H:Clock Pictures(KMP算法)
http://codeforces.com/gym/100502/attachments
题意:有两个时钟上面有n个指针,给出的数字代表指针的角度。问能否在某一时刻使得两个时钟的指针重合。
思路:容易想到先对指针角度排序,然后相邻指针相减得到一个间距。如果这些间距能够相同的话,那么就代表可以在某个时刻重合。
最暴力地做法就是O(n^2)的复杂度。用第一个时钟的每一个间距去匹配第二个时钟的每一个间距,如果发现有能够匹配到的就说明可以。
明明都想到匹配了,但是我以为可以贪心地做,但是一直WA。比赛之后听到是KMP。瞬间爆炸。= =太弱了。
因为是环状的,所以要让第一个时钟的间距向后延伸n-1个。
然后让第一个时钟的间距当文本串,第二个时钟的间距当模式串,然后跑一下KMP就好了。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define N 200010 4 const int maxdeg = 360000; 5 int nxt[N], a[N], b[N], c[N+N], d[N], n; 6 7 void make_next() { 8 for(int i = 0; i <= n; i++) nxt[i] = 1; 9 int k = 0, j = 1; 10 nxt[1] = 0; 11 while(j <= n) { 12 if(k == 0 || d[k] == d[j]) { 13 k++; j++; 14 nxt[j] = k; 15 } else k = nxt[k]; 16 } 17 } 18 19 bool KMP() { 20 int k = 1, j = 1; 21 make_next(); 22 while(j < 2 * n) { 23 if(k == 0 || d[k] == c[j]) { 24 k++; j++; 25 if(k == n) return true; 26 } else k = nxt[k]; 27 } 28 return false; 29 } 30 31 int main() { 32 scanf("%d", &n); 33 for(int i = 1; i <= n; i++) scanf("%d", &a[i]); 34 for(int i = 1; i <= n; i++) scanf("%d", &b[i]); 35 sort(a + 1, a + 1 + n); 36 sort(b + 1, b + 1 + n); 37 for(int i = 2; i <= n; i++) { 38 c[i] = a[i] - a[i-1]; 39 d[i] = b[i] - b[i-1]; 40 } 41 c[1] = a[1] - a[n] + maxdeg; 42 d[1] = b[1] - b[n] + maxdeg; 43 for(int i = n + 1; i < 2 * n; i++) 44 c[i] = c[i-n]; 45 if(KMP()) puts("possible"); 46 else puts("impossible"); 47 return 0; 48 }