题目大意:给出一个字符串,求出这是最少由多少个回文串组成的。回文串可以重叠。
思路:将原串中的所有回文串都统计出来,然后变成一些区间,问题就转化成了区间并的问题。
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