HDU 6103 Kirinriki 枚举中间点(思维)+ 尺取

来源:互联网 发布:安广网络宽带怎么样 编辑:程序博客网 时间:2024/05/16 12:17

传送门:HDU6103

题意:定义两个长度为n的字符串的距离为: disA,B=i=0n1|AiBn1i|  

问给定字符串中, 满足 dis <= m 两个不重叠子串的最大长度是多少。

思路:

先上官方题解:

标题提示我们回文串。

两个不重合的子串向中心一起延长会形成奇偶长度两种合串。

枚举一下中心向外延伸,如果和超过了阈值弹掉中心处的位置。双指针维护。

时间复杂度O(n^{2})O(n2)

另解:

枚举[1,i],[j,n]用同样方法往内缩。

时间复杂度O(n^{2})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;}/*1110aaabaa1aaabaa3aaayui10ak0abba0aaabcdefaaa*/





原创粉丝点击