USACO 5.1 Musical Themes(KMP,二分 / 暴力)
2015-03-29 21:52:30
思路:这题... 一开始用KMP暴力超时掉了... 套了个二分就过了。。 看比人貌似用暴力也可以过?。
二分枚举长度,可以证明若重复的theme长度L可行,那么l < L的也可行,符合单调性。
根据枚举的长度来枚举起点然后KMP即可。
1 /* 2 ID:naturec1 3 PROG: theme 4 LANG: C++ 5 */ 6 #include <cstdio> 7 #include <cstring> 8 #include <cstdlib> 9 #include <cmath> 10 #include <vector> 11 #include <map> 12 #include <set> 13 #include <stack> 14 #include <queue> 15 #include <string> 16 #include <iostream> 17 #include <algorithm> 18 using namespace std; 19 20 #define MEM(a,b) memset(a,b,sizeof(a)) 21 #define REP(i,n) for(int i=0;i<(n);++i) 22 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 23 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 24 #define MP(a,b) make_pair(a,b) 25 26 typedef long long ll; 27 typedef pair<int,int> pii; 28 const int INF = (1 << 30) - 1; 29 30 int N; 31 int v[5010],dif[5010]; 32 int P[5010]; 33 34 void Getnext(int len,int st){ 35 P[0] = -1; 36 int j = -1; //当前匹配到的前缀 37 for(int i = 1; i < len; ++i){ 38 while(j >= 0 && dif[st + j + 1] != dif[st + i]) j = P[j]; 39 if(dif[st + j + 1] == dif[st + i]) j++; 40 P[i] = j; 41 } 42 } 43 44 int main(){ 45 freopen("theme.in","r",stdin); 46 freopen("theme.out","w",stdout); 47 scanf("%d",&N); 48 REP(i,N) scanf("%d",v + i); 49 REP(i,N - 1) dif[i] = v[i + 1] - v[i]; 50 N--; 51 int ans = 0; 52 int l = 0,r = N / 2; 53 while(l <= r){ 54 int len = getmid(l,r); 55 int res = 0; 56 for(int st = 0; !res && st <= N - 2 * len; ++st){ 57 Getnext(len,st); 58 int j = -1; 59 bool flag = false; 60 for(int i = st + len + 1; i < N; ++i){ 61 while(j >= 0 && dif[st + j + 1] != dif[i]) j = P[j]; 62 if(dif[st + j + 1] == dif[i]) j++; 63 if(j == len - 1){ 64 flag = true; 65 break; 66 } 67 } 68 if(flag) res = len; 69 } 70 if(!res) r = len - 1; 71 else l = len + 1,ans = len; 72 //printf("len : %d , l,r : (%d,%d)\n",len,l,r); 73 } 74 if(ans + 1 < 5) printf("0\n"); 75 else printf("%d\n",ans + 1); 76 return 0; 77 }