https://nanti.jisuanke.com/t/30998

题意

给一串由0..9组成的数字字符串,求所有不同回文串的权值和。比如说“1121”这个串中有“1”,“2”,“11”,“121”三种回文串,他们的权值分别是1,2,11,121。最终输出ans=135。

分析

第一次知道马拉车是manacher。。。涨姿势了

在马拉车进行的过程中,进行子回文串的统计去重。

这里的哈希去重方法重点学习理解。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define ms(a, b) memset(a, b, sizeof(a))
#define pb push_back
#define mp make_pair
#define pii pair<int, int>
//#define eps 0.0000000001
#define IOS ios::sync_with_stdio(0);cin.tie(0);
#define random(a, b) rand()*rand()%(b-a+1)+a
#define pi acos(-1)
//const ll INF = 0x3f3f3f3f3f3f3f3fll;
const int inf = 0x3f3f3f3f;
const int maxn = 2e6 + ;
const int maxm = +;
const int mod = ; ull base=;
ull p[maxn<<],has[maxn<<];
ll pw[maxn<<],sum[maxn<<];
const int MOD=;
int head[maxn<<],nxt[maxn<<],cnt=;
ull val[maxn];
bool exist(ull now){
int u=now%MOD;
for(int i=head[u];i;i=nxt[i]){
if(val[i]==now) return true;
}
val[cnt]=now;
nxt[cnt]=head[u];
head[u]=cnt++;
return false;
}
ull gethas(int l,int r){
return has[r]-has[l-]*p[r-l+];
}
ll solve(int l,int r){
ull tmp=gethas(l,r);
if(exist(tmp)) return ;
ll ans=(sum[r]-sum[l-]*pw[(r-l++)/]%mod+mod)%mod;
return ans;
}
char s[maxn];
char Ma[maxn<<];
int Mp[maxn<<];
ll Manacher(char s[],int len){
int l=;
Ma[l++]='$';
Ma[l++]='#';
for(int i=;i<len;i++){
Ma[l++]=s[i];
Ma[l++]='#';
}
Ma[l]=;
pw[]=p[]=;
has[]=sum[]=;
for(int i=;i<=l;i++){
p[i]=p[i-]*base;
has[i]=has[i-]*base+Ma[i];
pw[i]=pw[i-]*%mod;
if(Ma[i]>=''&&Ma[i]<=''){
sum[i]=(sum[i-]*+Ma[i]-'')%mod;
}else{
sum[i]=sum[i-];
}
}
ll ans=;
int mx=,id=;
for(int i=;i<l;i++){
if(Ma[i]!='#') ans=(ans+solve(i,i))%mod;
Mp[i]=mx>i?min(Mp[*id-i],mx-i):;
while(Ma[i+Mp[i]]==Ma[i-Mp[i]]){
if(Ma[i+Mp[i]]!='#') ans=(ans+solve(i-Mp[i],i+Mp[i]))%mod;
Mp[i]++;
}
if(mx<i+Mp[i]){
mx=i+Mp[i];
id=i;
}
} return ans;
}
int main() {
#ifdef LOCAL
freopen("in.txt", "r", stdin);
// freopen("input.txt", "w", stdout);
#endif
scanf("%s",s);
int len=strlen(s);
printf("%lld\n",Manacher(s,len));
return ;
}

回文树的做法是先构建一颗回文树,然后dfs奇偶节点,当前节点的所代表的数字=当前添加的数字*pow(10,当前回文串长度-1) +他父亲的数字*10+当前添加的数字。

比如:33->1331  就是1*1000+33+1。此外有点卡空间,注意内存使用

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define ms(a, b) memset(a, b, sizeof(a))
#define pb push_back
#define mp make_pair
#define pii pair<int, int>
//#define eps 0.0000000001
#define IOS ios::sync_with_stdio(0);cin.tie(0);
#define random(a, b) rand()*rand()%(b-a+1)+a
#define pi acos(-1)
//const ll INF = 0x3f3f3f3f3f3f3f3fll;
const int inf = 0x3f3f3f3f;
const int maxn = 2e6 + ;
const int maxm = +;
const int mod = 1e9+; struct PAM{
int nxt[maxn][];
int fail[maxn];
int cnt[maxn];
int num[maxn];
int len[maxn];
int s[maxn];
int last,n,p; int newnode(int w){
for(int i=;i<;i++) nxt[p][i]=;
num[p]=cnt[p]=;
len[p]=w;
return p++;
}
void init(){
n=last=p=;
newnode();
newnode(-);
s[n]=-;
fail[]=;
}
int get_fail(int x){
while(s[n-len[x]-]!=s[n]) x=fail[x];
return x;
}
void add(int c){
c-='';
s[++n]=c;
int cur=get_fail(last);
if(!nxt[cur][c]){
int now=newnode(len[cur]+);
fail[now]=nxt[get_fail(fail[cur])][c];
nxt[cur][c]=now;
num[now]=num[fail[now]]+;
}
last=nxt[cur][c];
cnt[last]++;
}
void Count(){
for(int i=p-;i>=;i--) cnt[fail[i]]+=cnt[i];
}
};
PAM pam;
char s[maxn];
ll odd=;
ll even=;
ll qpow(ll a,ll b){
ll res=;
while(b){
if(b&) res=a*res%mod;
b>>=;
a=a*a%mod;
}
return res;
}
void dfs_odd(int x,ll fa){
for(int i=;i<=;i++){
if(pam.nxt[x][i]){
ll cur;
if(pam.len[pam.nxt[x][i]]==){
odd=(i+odd)%mod;
cur=i;
}else{
cur=(i*qpow(,pam.len[pam.nxt[x][i]]-)%mod+i+fa*%mod)%mod;
odd=(odd+cur%mod)%mod;
}
dfs_odd(pam.nxt[x][i],cur);
}
}
}
void dfs_even(int x,ll fa){
for(int i=;i<=;i++){
if(pam.nxt[x][i]){
ll cur=(i*qpow(,pam.len[pam.nxt[x][i]]-)%mod+i+fa*%mod)%mod;
even=(even+cur)%mod;
dfs_even(pam.nxt[x][i],cur);
}
}
}
int main() {
#ifdef LOCAL
freopen("in.txt", "r", stdin);
// freopen("input.txt", "w", stdout);
#endif
pam.init();
scanf("%s",s);
int len=strlen(s);
for(int i=;i<len;i++) pam.add(s[i]);
dfs_odd(,);
dfs_even(,);
printf("%lld\n",(odd+even)%mod); return ;
}

ACM-ICPC 2018 南京赛区网络预赛 I Skr (马拉车+hash去重)或(回文树)的更多相关文章

  1. ACM-ICPC 2018 南京赛区网络预赛 G Lpl and Energy-saving Lamps(模拟+线段树)

    https://nanti.jisuanke.com/t/30996 题意 每天增加m个灯泡,n个房间,能一次性换就换,模拟换灯泡过程.询问第几天的状态 分析 离线做,按题意模拟.比赛时线段树写挫了. ...

  2. ACM-ICPC 2018 南京赛区网络预赛 I. Skr(回文树)

    题意 https://nanti.jisuanke.com/t/A1955 求所有本质不同的回文串转成数后的和. 思路 如果了解回文树的构造原理,那么这题就很简单了,回文树每个结点代表一个回文串,每添 ...

  3. ACM-ICPC 2018 南京赛区网络预赛 J.sum

    A square-free integer is an integer which is indivisible by any square number except 11. For example ...

  4. ACM-ICPC 2018 南京赛区网络预赛 E题

    ACM-ICPC 2018 南京赛区网络预赛 E题 题目链接: https://nanti.jisuanke.com/t/30994 Dlsj is competing in a contest wi ...

  5. ACM-ICPC 2018 南京赛区网络预赛B

    题目链接:https://nanti.jisuanke.com/t/30991 Feeling hungry, a cute hamster decides to order some take-aw ...

  6. 计蒜客 30999.Sum-筛无平方因数的数 (ACM-ICPC 2018 南京赛区网络预赛 J)

    J. Sum 26.87% 1000ms 512000K   A square-free integer is an integer which is indivisible by any squar ...

  7. 计蒜客 30996.Lpl and Energy-saving Lamps-线段树(区间满足条件最靠左的值) (ACM-ICPC 2018 南京赛区网络预赛 G)

    G. Lpl and Energy-saving Lamps 42.07% 1000ms 65536K   During tea-drinking, princess, amongst other t ...

  8. 计蒜客 30990.An Olympian Math Problem-数学公式题 (ACM-ICPC 2018 南京赛区网络预赛 A)

    A. An Olympian Math Problem 54.28% 1000ms 65536K   Alice, a student of grade 66, is thinking about a ...

  9. ACM-ICPC 2018 南京赛区网络预赛 B. The writing on the wall

    题目链接:https://nanti.jisuanke.com/t/30991 2000ms 262144K   Feeling hungry, a cute hamster decides to o ...

随机推荐

  1. 【BZOJ1426】收集邮票 期望DP

    题目大意 有\(n\)种不同的邮票,皮皮想收集所有种类的邮票.唯一的收集方法是到同学凡凡那里购买,每次只能买一张,并且买到的邮票究竟是\(n\)种邮票中的哪一种是等概率的,概率均为\(\frac{1} ...

  2. linux 定时任务到秒级

    linux crontab 只有到分钟级别的 有两种方法 方法1.写个sh脚本,循环(下例为每秒访问一次百度) #! /bin/bash PATH=/bin:/sbin:/usr/bin:/usr/l ...

  3. 【java+selenium】网易云音乐刷累计听歌数

    背景应该是在去年的时候,刷知乎看到一个问题,大概是说怎么刷网易云音乐个人累计听歌数,然后有一个高赞回答,贴了一段js代码,直接在浏览器console执行就可以了.当时试了下,直接一下子刷了有好几万.悲 ...

  4. android 异常信息The specified child already has a parent. You must call removeView() on the child's parent first. 的处理方法

    [Android异常信息]: The specified child already has a parent. You must call removeView() on the child's p ...

  5. 【BZOJ4832】抵制克苏恩(矩阵快速幂,动态规划)

    [BZOJ4832]抵制克苏恩(矩阵快速幂,动态规划) 题面 BZOJ 题解 一模一样 #include<iostream> #include<cstdio> using na ...

  6. rt-thread之stm32系列BSP制作方法

    @2019-01-24 [小记] bsp制作方法: 官网下载 rt-thread 源码,将路径 bsp/stm32/libraries/templates/ 下的模板文件,Copy至路径 bsp/st ...

  7. CCCC 喊山

    2016年天梯赛模拟&初赛题集(nwu) 编程题30小题,共计580分 580分 编程题 5-14 喊山   (30分) 喊山,是人双手围在嘴边成喇叭状,对着远方高山发出“喂—喂喂—喂喂喂…… ...

  8. cf571B Minimization (dp)

    相当于是把%k相同的位置的数分为一组,组与组之间互不干扰 然后发现一组中可以任意打乱顺序,并且一定是单调排列最好,那个值就是最大值减最小值 所以我给所有数排序以后,同一组应该选连续的一段最好 然后发现 ...

  9. LOJ#6284. 数列分块入门 8

    分块的时候开一个数组标记这个区间是不是都是一样颜色的部分,如果是的话,我后面的查询,更新部分就可以直接整块操作,对于不是不全部都一样颜色的块在具体进到快里面去暴力. 在更新的时候对边上的两个不完整的块 ...

  10. jsp model1

    一.model1(纯jsp技术): 1.dao:data access object,数据访问对象,即专门对数据库进行操作的类,一般说dao不含业务逻辑. 2.当进行跳转时候,需要用servlet来实 ...