BZOJ 3790 神奇项链 Hash+二分

题目大意:给出一个字符串,求出这是最少由多少个回文串组成的。回文串可以重叠。

思路:将原串中的所有回文串都统计出来,然后变成一些区间,问题就转化成了区间并的问题。

CODE:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 400010
#define BASE 1333
#define INF 0x3f3f3f3f
using namespace std;
#define min(a,b) ((a) < (b) ? (a):(b))

int length;
char _s[MAX],s[MAX];
unsigned long long hash[MAX],_hash[MAX],power[MAX];

struct Interval{
	int x,y;

	Interval(int _ = 0,int __ = 0):x(_),y(__) {}
	bool operator <(const Interval &a)const {
		if(x == a.x)	return y > a.y;
		return x < a.x;
	}
}block[MAX];

Interval GetMosl(int pos)
{
	int l = 1,r = min(pos,length - pos + 1),ans = 0;
	while(l <= r) {
		int mid = (l + r) >> 1;
		unsigned long long h1 = hash[pos + mid - 1] - hash[pos - 1] * power[mid];
		unsigned long long h2 = _hash[pos - mid + 1] - _hash[pos + 1] * power[mid];
		if(h1 == h2)	ans = mid,l = mid + 1;
		else	r = mid - 1;
	}
	return Interval(pos - ans + 1,pos + ans - 1);
}

int fenwick[MAX];

inline void Fix(int x,int c)
{
	for(; x; x -= x&-x)
		fenwick[x] = min(fenwick[x],c);
}

inline int GetAns(int x)
{
	int re = INF;
	for(; x <= length; x += x&-x)
		re = min(re,fenwick[x]);
	return re;
}

int main()
{
	power[0] = 1;
	for(int i = 1; i < MAX; ++i)	power[i] = power[i - 1] * BASE;
	while(scanf("%s",_s + 1) != EOF) {
		length = strlen(_s + 1);
		s[1] = '$';
		for(int i = 1; i <= length; ++i)
			s[i << 1] = _s[i],s[i << 1|1] = '$';
		s[(length + 1) << 1] = '\0';
		length = strlen(s + 1);
		for(int i = 1; i <= length; ++i)	hash[i] = hash[i -  1] * BASE + s[i];
		_hash[length + 1] = 0;
		for(int i = length; i; --i)		_hash[i] = _hash[i + 1] * BASE + s[i];
		for(int i = 1; i <= length; ++i)
			block[i] = GetMosl(i);
		sort(block + 1,block + length + 1);
		memset(fenwick,0x3f,sizeof(fenwick));
		Fix(1,-1);
		for(int temp,i = 1; i <= length; ++i) {
			temp = GetAns(block[i].x);
			Fix(block[i].y,temp + 1);
		}
		printf("%d\n",GetAns(length));
	}
	return 0;
}
时间: 2024-10-03 23:02:33

BZOJ 3790 神奇项链 Hash+二分的相关文章

BZOJ 3790 神奇项链 Hash+二分+树状数组

题目大意:给定一个串,问这个串最少可以由回文串拼接多少次而成(拼接可以重叠) 首先将每两个字符之间插入占位符,然后Hash+二分搞出所有极大回文串(可以用manacher,我不会) 问题转化成了给定一些区间,求最少的能覆盖整个数轴的区间 将所有区间按照某一端点排序 然后上树状数组即可 回头还是去学学manacher吧... #include <cstdio> #include <cstring> #include <iostream> #include <algo

BZOJ 3790 神奇项链 hash/后缀自动机+贪心

Description 母亲节就要到了,小 H 准备送给她一个特殊的项链.这个项链可以看作一个用小写字母组成的字符串,每个小写字母表示一种颜色. 为了制作这个项链,小 H 购买了两个机器.第一个机器可以生成所有形式的回文串,第二个机器可以把两个回文串连接起来,而且第二个机器还有一个特殊的性质:假如一个字符串的后缀和一个字符串的前缀是完全相同的,那么可以将这个重复部分重叠.例如:aba和aca连接起来,可以生成串abaaca或 abaca. 现在给出目标项链的样式,询问你需要使用第二个机器多少次才

BZOJ 3790 神奇项链(manacher+DP+树状数组)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3790 [题目大意] 问最少用几个回文串可以构成给出串,重叠部分可以合并 [题解] 我们先用manacher处理出每个位置最长的回文串, 那么题目就转化为求最少的线段来覆盖全区间,那就是经典的dp题了, dp[i]=min(dp[j]+1)(i线段的左端点-1和j线段的右端点有交) 用树状数组优化一下即可. [代码] #include <cstdio> #include <al

bzoj 3790 神奇项链(Manacher,DP+BIT | 贪心)

[题意] 你可以产生一个回文串,也可以将两个串合并成一个串,问产生目标串需要的最少合并次数. [思路] Manacher求出每个位置可以向两边延伸的最长回文串. 则题目转化为有若干条线段,求最少的线段将[1..n]覆盖.贪心DP皆可上,DP需要BIT优化一下. [代码] 1 #include<set> 2 #include<cmath> 3 #include<queue> 4 #include<vector> 5 #include<cstdio>

ZZULI 1876: 蛤玮的项链 Hash + 二分

Time Limit: 6 Sec  Memory Limit: 128 MBSubmit: 153  Solved: 11 SubmitStatusWeb Board Description 蛤玮向心仪的妹子送了一条项链,这条项链是由小写字母构成的首尾相接的字符串,妹子看了看项链对蛤玮说,"我希望它是对称的",蛤玮想了想之后决定,从项链上截取出一段,这段如果是回文的话那么妹子戴起来就是对称的了.由于蛤玮会魔法,他可以把项链上的某一个字母变成任意另一个字母,但由于魔力限制他最多只能变两

【BZOJ】【3790】神奇项链

Manacher算法/DP 找出所有的回文串,看做是一个个线段,那么问题就转化成了用最少的线段将整个区间覆盖起来,可以重叠,那么这就是一个DP了= = Orz ZKY大爷,让蒟蒻开眼界了……头一次知道原来树状数组还可以反过来用0.0 1 /************************************************************** 2 Problem: 3790 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6

【BZOJ-3790】神奇项链 Manacher + 树状数组(奇葩) + DP

3790: 神奇项链 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 304  Solved: 150[Submit][Status][Discuss] Description 母亲节就要到了,小 H 准备送给她一个特殊的项链.这个项链可以看作一个用小写字母组成的字符串,每个小写字母表示一种颜色.为了制作这个项链,小 H 购买了两个机器.第一个机器可以生成所有形式的回文串,第二个机器可以把两个回文串连接起来,而且第二个机器还有一个特殊的性质:假如一个

BZOJ 2565 最长双回文串 Hash+二分

题目大意:给定一个字符串,求一个最长的子串,该字串可以分解为两个回文子串 傻逼的我又忘了Manacher怎么写了= = 无奈Hash+二分吧 首先将字符串用分隔符倍增,然后求出以每个点为中心的最长回文半径 然后考虑两个回文串怎么合并成一个 我们发现图中以i为中心的回文串和以j为中心的回文串合并后长度恰好为(j-i)*2 能合并的前提是以两个点为中心的回文串有交点 那么对于每个j我们要求出有交点的最左侧的i 维护一个后缀min随便搞搞就可以了 #include <cstdio> #include

【BZOJ】1014: [JSOI2008]火星人prefix(splay+hash+二分+lcp)

http://www.lydsy.com/JudgeOnline/problem.php?id=1014 被sb错调哭了QAQ...insert那里..插入到第x个后边...我......写成了第x个前面..........还调了!好!久! QAQ 本题神lcp做法....表示只会sa的height的离线.......这种在线的我就QAQ做个忧伤的表情... 然后膜拜了题解....好神..splay维护区间...hash+二分维护lcp....QAQ似乎是白书上说的么... 但是这种有概率的题这