题意:
给一个个数为 n 数组 a,求连续且能分成等长的三段的最长的长度,三段关系:第一段和第二段对应元素满足回文,第一段和第三段对应元素相等相等,也就是说第二段和第三段也满足回文。思路:
这个自然想到用求回文串的manacher算法解。manacher步骤参考最长回文 made by xingyeyongheng。
依样画葫芦,记 dp[i] 为每个以下标 i 的回文串的半径,然后依次遍历插入的元素的半径,更新: ans = i - j ( j - i > ans && j < i + dp[i])
答案就是:ans / 2 * 3(注:ans 初始值赋为-1, 计算时数组a是扩展了的)
开始小傻子我还是傻傻得想用另外一种算法做,感觉应该可以,无奈超时严重,后来用manacher加上遍历,就过了,本来wwdd还肯定我这个会超时,想不到过了,想来是我这个朴素的方法还是可行的, 也比较容易理解。复杂度:
时间复杂度:O(n^2)
空间复杂度:O(n)ac代码
/* ***********************************************
Author :Ilovezilian
Created Time :2015/8/11 22:59:46
File Name :1003_2.cpp
************************************************ */
#include <bits/stdc++.h>
#define fi(i,n1,n) for(int i = n1; i <= n; i ++)
#define fd(i,n1,n2) for(int i = n1; i >= n2; i --)
#define INF 0x7fffffff
#define ll long long
using namespace std;
const int N = 100010, mod = 1e9+7;
int a[N<<1], dp[N<<1];
int main()
{
//freopen("","r",stdin);
//freopen("","w",stdout);
int cas, n, ans;
scanf("%d", &cas);
fi(ccas, 1, cas)
{
memset(a, -1, sizeof(a));
memset(dp, 0, sizeof(dp));
scanf("%d", &n);
fi(i,1,n) scanf("%d", a + i*2);
int len = n * 2, id = 0;
a[0] = -2, a[len+2] = -3;
dp[0] = dp[1] = dp[len+1] = 1;
fi(i, 2, len + 1)
{
if(dp[id] + id > i) dp[i] = min(dp[id*2-i], dp[id] + id - i);
else dp[i] = 1;
while(a[i+dp[i]] == a[i-dp[i]]) dp[i] ++;//i + dp[i] <= len + 1 && i - dp[i] >= 1 &&
if(dp[id] + id < i + dp[i]) id = i;
}
ans = -1;
//fi(i,1,n) dp[i] = dp[i*2]/2;
for(int i = 1; i <= len+1; i += 2) if(dp[i] + i <= len + 1)
{
for(int k = ans + 2; k <= dp[i]; k += 2)
//if(dp[i] <= dp[i+k-1] || dp[i+k-1] >= dp[i])
if(dp[i] >= k && dp[i + k - 1] >= k)
ans = k;
}
//fi(i,1,len+1) printf("dp[%d] = %d\n", i, dp[i]);
if(ans == 1) ans = 0;
printf("Case #%d: %d\n",ccas, ans / 2 * 3);
}
return 0;
}
- 超时代码
/* ***********************************************
Author :Ilovezilian
Created Time :2015/8/11 16:42:25
File Name :1003_1.cpp
************************************************ */
#include <bits/stdc++.h>
#define fi(i,n1,n) for(int i = n1; i <= n; i ++)
#define fd(i,n1,n2) for(int i = n1; i >= n2; i --)
#define INF 0x7fffffff
#define ll long long
using namespace std;
const int N = 100010, mod = 1e9+7;
int a[N], n, ans;
int main()
{
//freopen("","r",stdin);
//freopen("","w",stdout);
int cas, zz = 1;
scanf("%d", &cas);
while(cas--)
{
scanf("%d", &n);
fi(i,1,n) scanf("%d", a + i);
ans = 0;
fi(i,1,n-1)
{
if(i + ans * 2 > n) break;
if(a[i] == a[i+1])
{
int lr = min(i*3, n);
for(int j = i + ans*2 + 2; j <= lr; j += 2) if(a[j] == a[i])
{
int len = (j - i) / 2;
///printf("j = %d len = %d\n", j, len);
bool ok = 1;
for(int k = 1; k < len; k ++) if(a[i-k] != a[i+k+1] || a[i-k] != a[j-k])
{
// printf("a[%d] = %d a[%d] = %d a[%d] = %d\n", i-k, a[i-k], i + k + 1, a[i+k+1], j - k, a[j-k]);
ok = 0;
break;
}
if(ok) ans = len;
}
}
}
printf("Case #%d: %d\n", zz ++, ans * 3);
}
return 0;
}