[POI 2010] ANT-Antisymmetry

链接

好像回文串的子串问题,似乎可以用马拉车算法(manacher)来写

这道题本质上就是看左右对称的两点处的值和是否为1(对应回文串的相等)

但是,与回文串不同的是,奇数的串显然不符合题意,因此我们只需要考虑偶数串即可

我们得到以每个点为中心的最长符合题意的字符串之后

我们发现,只要是以该处为中心,任意长度小于最长半径的字符串都符合题意

比如111000,中心是0(由于偶数的中心很尴尬,我们取右边一个)

那么,1100,10都符合题意

因此我们只需要将得到的半径相加即可

代码如下:

#include<iostream>
#include<vector>
using namespace std;

long long manacher(string& s) {
	int n = s.size();
	vector<int>a(n);
	int l = 0, r = -1;
	for (int i = 0;i < n;i++) {
		int k = i > r ? 0 : min(a[r + l - i + 1], r - i + 1);
		while (i - k - 1 >= 0 && i + k < n && s[i - k - 1] + s[i + k] == '0' + '1') k++;
		a[i] = k;
		if (i + k - 1 > r) {
			l = i - k;
			r = i + k - 1;
		}
	}
	long long res = 0;
	for (int i = 0;i < n;i++) {
		res += a[i];
	}
	return res;
}

int main() {
	int n;
	cin >> n;
	string str;
	cin >> str;
	cout << manacher(str);
}

时间复杂度:O(n)

空间复杂度:O(n)

当然,这题还能用哈希写(本来就是我用来练哈希的)

我们设置两个哈希h和rh

h记录的是原字符串的某个进制

rh记录的是原字符串变换(1变成0,0变成1)后再反转的某个进制

接着用二分法求出最大半径(怎么求?我比对二者的哈希值是否相等就行了,不过要注意,rh和h是对称的)

代码如下:

#include<vector>
using namespace std;
#define ull unsigned long long
const int base = 233;
vector<ull>h, rh, b;


ull f(string& s, string& rs) {
	int n = s.size();
	ull res = 0;
	for (int i = 1;i <= n;i++) {
		int l = 0, r = min(i - 1, n - i + 1);
		int ans = 0;
		while (r >= l) {
			int mid = (l + r) / 2;
			int right = i + mid - 1, left = i - mid;
			ull h1, h2;
			h1 = h[right] - h[left - 1] * b[right - left + 1];
			h2 = rh[n - left + 1] - rh[n - right] * b[right - left + 1];
			if (h1 != h2) {
				r = mid - 1;
			}
			else {
				l = mid + 1;
				ans = mid;
			}
		}
		res += ans;
	}
	return res;
}


int main() {
	int n;
	string str;
	cin >> n >> str;
	h.assign(n + 1, 1);
	rh.assign(n + 1, 1);
	b.assign(n + 1, 1);
	string rs;
	for (int i = n - 1;i >= 0;i--) {
		rs += str[i] == '1' ? '0' : '1';
	}
	for (int i = 1;i <= n;i++) {
		b[i] = b[i - 1] * base;
		h[i] = h[i - 1] * base + str[i - 1] - 'a';
		rh[i] = rh[i - 1] * base + rs[i - 1] - 'a';
	}
	cout << f(str, rs);
}

时间复杂度:O(n log n)

空间复杂度:O(n)

全部评论

相关推荐

03-22 00:32
已编辑
门头沟学院 golang
互联网会让我们变得需求过高。​当我们获得了想要的,就会开始想要别的。一个人的欲望永远无法被满足,如果他不满足于现在拥有的事物的话。​在牛客上看了一些双非本面试后端的经历,也是感受到了临近大四的压力。​我觉得很大的误区在于我们一开始就给自己定了一个太高的目标了。宏伟的志向从来不因为它本身而实现,而是归结到每一步的踏实。战略上要长远瞄定,战术上却要着眼当下,我将此奉为信条。可我们心中的那个目标,其实总是会随着我们的视野增长而发生变化。互联网上的信息太多,简直是要爆炸了,我们发展了几万年的原始头脑根本无法承受这样的数量级,所以焦虑自然会迎头而来。所以要少接触无效比较的信息,在网上跟你比的,也许是一群永远见不上的凤毛麟角,也许是他们的出生、天赋或者各种我们已经无法改变的事情造就了他们。​但这些不是一个人应当关心的,当注意力被集中在了对比,他总会本能地去寻找高于自己的而忽略了不及视野的事物。于是体现在计算机行业上就是,觉得不进入大厂就是在摆烂,觉得那些佬好牛,膜膜膜。实际上不是的,我可以赚的少一点,但我愿意开心一点,毕竟难得自己选上了这条路,难得排除万难,也难得走到了今天,其实并非没意义,踏踏实实做下去就可以。实际上我们过于在意大厂还是中厂还是小厂了,不同的薪资待遇需要不同的能力与机遇去获取,也需要承担不同的责任。更明显的,优秀明明是相对而言的,也许收到大厂offer的双非本真的千里挑一,这根本就不意味着人人都要做那千分之一。反而先意识到这点,才更好静的下来。少点焦虑不好吗,即使我们明知这种情绪百害无一利?​观察行业动向当然是有意义的,我的战略就是能拿下中小厂实习即可,不挑食。那么鉴于golang职位所在位置多处于大厂、高学历这些标签之间,而java依旧是后端不二之选,我决定接下来转java深入学习,做出几个项目来先,然后golang简历可以试着投一投。这个学期能面试到就试试水,八股文不管如何都是要背的,手撕算法之类不是我定位的重点。​鲜花都为你盛开,美景都为你常在,永远爱着你的我,你不必非要做任何......
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务