传送门:HDU6103
题意:定义两个长度为n的字符串的距离为: disA,B=∑i=0n−1|Ai−Bn−1−i|
问给定字符串中, 满足 dis <= m 两个不重叠子串的最大长度是多少。
思路:
先上官方题解:
标题提示我们回文串。
两个不重合的子串向中心一起延长会形成奇偶长度两种合串。
枚举一下中心向外延伸,如果和超过了阈值弹掉中心处的位置。双指针维护。
时间复杂度O(n2)
另解:
枚举[1,i],[j,n]用同样方法往内缩。
时间复杂度O(n2)
主要就是怎么快速并且不重复的枚举所有子串的情况,从开始暴力的话显然是n^3的复杂度,
因为我们重复计算了好多部分,
然而我们换种暴力的方式就可以大幅削减重复计算部分,因为两个字符串的dis是类似回文串一样的计算,
所以可以考虑枚举对称中心,关于每个中心轴我们再用尺取法去寻找
关于该中心轴对称的两个dis <= m的最长子串,
因为尺取法能极大化利用上一次的计算结果,而枚举对称中心又保证了我们不会遗漏情况,
这样就将纯暴力的N^3复杂度降到了N^2.
注意对称中心不一定是某个字符,还有可能是字符之间的空当。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int>P;
const int MAXN=100010;
char s[5005];
inline int abs(int t)
{
return t < 0 ? -t : t;
}
inline int max(int a, int b)
{
return a > b ? a : b;
}
int main()
{
int T;
cin >> T;
while(T--)
{
int m;
scanf("%d %s", &m, s + 1);
int len = strlen(s + 1);
int l1, r1, l2, r2, tmp;
int ans = 0;
for(int i = 1; i <= len; i++)
{
//以第i - 1个字符和第i个字符之间的空为对称轴
l1 = r1 = i - 1;
l2 = r2 = i;
tmp = 0;
while(l1 >= 1 && r2 <= len)
{
tmp += abs(s[l1] - s[r2]);
while(tmp > m && l1 <= r1 && l2 <= r2)
tmp -= abs(s[r1--] - s[l2++]);
if(tmp <= m)
ans = max(ans, r1 - l1 + 1);
l1--;
r2++;
}
if(tmp <= m && l1 >= 1 && r2 <= len)
ans = max(ans, r1 - l1 + 1);
//以第i个字符为对称轴
l1 = r1 = i - 1;
l2 = r2 = i + 1;
tmp = 0;
while(l1 >= 1 && r2 <= len)
{
tmp += abs(s[l1] - s[r2]);
while(tmp > m && l1 <= r1 && l2 <= r2)
tmp -= abs(s[r1--] - s[l2++]);
if(tmp <= m)
ans = max(ans, r1 - l1 + 1);
l1--;
r2++;
}
if(tmp <= m && l1 >= 1 && r2 <= len)
ans = max(ans, r1 - l1 + 1);
}
cout << ans << endl;
}
return 0;
}
/*
111
0
aaabaa
1
aaabaa
3
aaayui
10
ak
0
abba
0
aaabcdefaaa
*/