您的位置:首页 > 大数据 > 人工智能

HDU 5785 Interesting 2016 Multi-University Training Contest 5(Manacher)

2016-08-03 22:48 453 查看
题目链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1005&cid=708

题意:对于长度1e6的字符串,某个字串区间[L, R]若可以分割成两个回文字串[L, mid]和[mid + 1, R],那么这个区间的权值为L * R, 不能分割则权值为0, 求所有区间的权值和。

思路:用manacher算法O(n)求出所有的回文半径。有了回文半径后,就可以求出cntL[i]表示以i结尾的回文串的起始位置的和cntR[i]表示以i起始的回文串的结尾位置的和,然后就可以求出答案了,这里要注意奇偶长度回文串的不同处理。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <iostream>
#include <string>
#include <cmath>
#include <vector>
#include <set>
#include <map>
using namespace std;

#define REP(i, a, b) for (int i = (a), i##_end_ = (b); i < i##_end_; ++i)
#define MP make_pair
#define PB push_back
#define SZ(x) (int((x).size()))
#define ALL(x) (x).begin(), (x).end()
#define X first
#define Y second
template<typename T> inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }

template <class T>
inline bool RD(T &ret) {
char c; int sgn;
if (c = getchar(), c == EOF) return 0;
while (c != '-' && (c<'0' || c>'9')) c = getchar();
sgn = (c == '-') ? -1 : 1 , ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
template <class T>
inline void PT(T x) {
if (x < 0) putchar('-') ,x = -x;
if (x > 9) PT(x / 10);
putchar(x % 10 + '0');
}

const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef pair<int, int> pii;
typedef long double LD;

const LL MOD = 1e9 + 7;

const int N = 1e6 + 100;
int Mp[N<<1];
char Ma[N<<1];

LL Lcnt
, Rcnt
, OLcnt
, ORcnt
;
LL Lval
, Rval
, OLval
, ORval
;
LL Lsum
, Rsum
;

void add(LL &a, LL val) {
a += val;
if(a >= MOD) a -= MOD;
}
void Manacher(char s[],int len)
{
int l = 0;
Ma[l++] = '$';
Ma[l++] = '#';
for(int i=0;i<len;i++){
Ma[l ++] = s[i];
Ma[l++] = '#';
}
Ma[l] = 0;
int mx = 0,id = 0;
for(int i = 1;i < l ;i ++){
Mp[i]= mx>i? min(Mp[2*id-i],mx-i) :1;
while(Ma[Mp[i]+i ] == Ma[i-Mp[i] ]) Mp[i]++;
if(Mp[i]+i > mx){
mx = Mp[i]+i;
id = i;
}
if(Mp[i] >= 2){
int L = (i-Mp[i])>>1; //逆推到原串中的区间左端点
int R = (i+Mp[i]-4)>>1; //逆推到原串中的区间右端点
L ++, R ++;
Lcnt[L] ++;
Rcnt[R] ++;
add(Lval[L], (L + R) / 2 * 2 + (R - L) % 2);
add(Rval[R], (L + R) / 2 * 2 + (R - L) % 2);
int one = 1;
if((L + R) % 2 == 0) {
add(OLcnt[(L + R) / 2], one);
add(ORcnt[(L + R) / 2], one);
add(OLval[(L + R) / 2], (L + R) / 2 * 2 + (R - L) % 2);
add(ORval[(L + R) / 2], (L + R) / 2 * 2 + (R - L) % 2);
} else {
add(OLcnt[(L + R) / 2], one);
add(ORcnt[(L + R) / 2 + 1], one);
add(OLval[(L + R) / 2], (L + R) / 2 * 2 + (R - L) % 2);
add(ORval[(L + R) / 2 + 1], (L + R) / 2 * 2 + (R - L) % 2);
}
}
}
}

char s
;
int main() {
while(~ scanf("%s", s)) {
int len = strlen(s);
for(int i = 0; i <= len; i ++) {
Lcnt[i] = Rcnt[i] = OLcnt[i] = ORcnt[i] = Lval[i] = Rval[i] = Lsum[i] = Rsum[i] = OLval[i] = ORval[i] = 0;
}
Manacher(s, len);
LL cur = 0, c = 0;
for(int i = 1; i <= len; i ++) {
add(cur, Lval[i]);
add(c, Lcnt[i]);
Rsum[i] = (cur - (i * c) % MOD + MOD) % MOD;
cur = (cur - OLval[i] + MOD) % MOD;
c = (c - OLcnt[i] + MOD) % MOD;
}
cur = c = 0;
for(int i = len; i >= 1; i --) {
add(cur, Rval[i]);
add(c, Rcnt[i]);
Lsum[i] = (cur - (i * c) % MOD + MOD) % MOD;
cur = (cur - ORval[i] + MOD) % MOD;
c = (c - ORcnt[i] + MOD) % MOD;
}
LL res = 0;
for(int i = 1; i < len; i ++) res = (res + Lsum[i] * Rsum[i + 1]) % MOD;
printf("%lld\n", res);

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: