容易联想到利用manacher算法获得len数组,然后枚举第二段的长度判断能否和第三段对应上,能的话就更新答案。
另外枚举长度的时候,小于等于当前答案的长度就没有必要枚举了,不然可能会超时。
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 6 const int N = 100007; 7 int num[N]; 8 int tmp[N << 1]; 9 int len[N << 1]; 10 int n; 11 12 int min( int x, int y ) 13 { 14 return x < y ? x : y; 15 } 16 17 void convert( int * st, int * dst ) 18 { 19 int l = 2 * n; 20 dst[0] = -1; 21 for ( int i = 1; i <= l; i += 2 ) 22 { 23 dst[i] = -2; 24 dst[i + 1] = st[i / 2]; 25 } 26 dst[2 * n + 1] = -2; 27 dst[2 * n + 2] = -3; 28 } 29 30 void manacher( int * st, int * dst ) 31 { 32 convert( st, dst ); 33 int l = 2 * n + 1; 34 int mx = 0, po = 0; 35 for ( int i = 1; i <= l; i++ ) 36 { 37 if ( mx > i ) 38 { 39 len[i] = min( mx - i, len[2 * po - i] ); 40 } 41 else 42 { 43 len[i] = 1; 44 } 45 while ( dst[i - len[i]] == dst[i + len[i]] ) 46 { 47 len[i]++; 48 } 49 if ( len[i] + i > mx ) 50 { 51 mx = len[i] + i; 52 po = i; 53 } 54 } 55 } 56 57 int main () 58 { 59 int t; 60 scanf("%d", &t); 61 for ( int _case = 1; _case <= t; _case++ ) 62 { 63 scanf("%d", &n); 64 for ( int i = 0; i < n; i++ ) 65 { 66 scanf("%d", num + i); 67 } 68 manacher( num, tmp ); 69 int ans = 0, l = 2 * n + 1; 70 for ( int i = 1; i <= l; i += 2 ) 71 { 72 for ( int j = i + len[i] - 1; j - i > ans; j -= 2 ) 73 { 74 if ( j - i + 1 <= len[j] ) 75 { 76 ans = j - i; 77 break; 78 } 79 } 80 } 81 ans = ans / 2 * 3; 82 printf("Case #%d: %d ", _case, ans); 83 } 84 return 0; 85 }