2018 ICPC 南京网络赛 skr

题意:

给出一个字符串,求它的所有回文子串转化成数字的和,对1e9+7取模。

题解:

先上Manacher,然后枚举每个点,按照半径从大到小的顺序枚举回文串,遇到出现过的就break,统计答案即可。

注意的是,判重时只能用pb_ds中的gp_hash_table,unordered_map会T,同时需要两个字符串hash关键子,一个会WA。

Manacher+暴力枚举回文串+pb_ds的hash_talbe判重+2个关键字的字符串hash。

 

代码:

#include<bits/stdc++.h>
#include<hash_map>
#define N 2000010
#define INF 0x3f3f3f3f
#define eps 1e-10
#define pi 3.141592653589793
#define LL long long
#define pb push_back
#define cl clear
#define si size
#define lb lowwer_bound
#define mem(x) memset(x,0,sizeof x)
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define P 1000000007
#define mod 998244353
using namespace std;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/priority_queue.hpp>
using namespace __gnu_pbds;

char s[N],ss[N<<1];
int H[N],A[N],r[N<<1],p[N],pp[N],len;
gp_hash_table<LL,bool>mp;

int Init()
{
    int len = strlen(s+1);
    ss[0] = '$';ss[1] = '#';
    int j = 2;
    for (int i = 1; i <= len; i++)ss[j++] = s[i],ss[j++] = '#';
    ss[j] = '\0';
    return j;
}

void Manacher()
{
    len=Init();
    int p,mx=0;
    for (int i = 1; i < len; i++)
    {
        if (i<mx) r[i]=min(r[2*p-i],mx-i);else r[i] = 1;
        while (ss[i-r[i]]==ss[i+r[i]]) r[i]++;
        if (mx<i+r[i])p=i,mx=i+r[i];
    }
}

inline int cal(int x,int y)
{
    return (H[y]-(LL)H[x-1]*p[y-x+1]%mod+mod)%mod;
}

inline int call(int x,int y)
{
    return (A[y]-(LL)A[x-1]*pp[y-x+1]%P+P)%P;
}

int main()
{
    while(~scanf("%s",s+1))
    {
        int n=strlen(s+1); p[0]=1;pp[0]=1;
        for (int i=1;i<=n;i++) A[i]=((LL)A[i-1]*10+(s[i]-'0'))%P,H[i]=((LL)H[i-1]*377+s[i])%mod,
                               p[i]=(LL)p[i-1]*377%mod,pp[i]=(LL)pp[i-1]*10%P;
        Manacher();
        int ans=0;mp.clear();
        for (int i=2;ss[i];i++)
        {
            if (ss[i]=='#' && r[i]==1) continue;
            int x=i/2-r[i]/2+1,y=i/2+r[i]/2-!(i&1);
            while(x<=y)
            {
                LL t=cal(x,y),tt=call(x,y);
                if (mp[(t<<31)|tt]) break;
                ans=(ans+tt)%P;
                mp[(t<<31)|tt]=1;
                x++;y--;
            }
        }
        printf("%d\n",ans);
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值