hdu多校赛第5场(hdu5785)

6 篇文章 0 订阅
2 篇文章 0 订阅

hdu5785 Interesting

题意

给你个三元组(i,j,k) 满足1≤i≤j< k≤length(S), S[i..j] and S[j+1..k] are all palindrome strings,问对于所有这个三元组,i*k和是多少。

解法

先跑一遍manacher不多说。

我在这里处理了四个数组:C1,C2,C3,C4

C1:代表对于下标i的点,他所在的回文串(回文串在他右边)中心下标*2的和

C2:代表对于下标i的点,他所在的回文串个数(回文串在他右边)

C3:代表对于下标i的点,他所在的回文串(回文串在他左边)中心下标*2的和

C4:代表对于下标i的点,他所在的回文串个数(回文串在他左边)

本可以O(N)时间处理出这四个数组,结果比赛时候犯傻了用了四个树状数组,然后GG

因为处理这四个数组虽然是对区间的更新,但是并没有查询,只要算出结果就行,所以可以O(N)出来,mdzz

我的想法是把manacher上的结果映射到原来的字符串上进行计数,然后写写懵B了,lv男神直接在manacher上数组上做了计数(666)
不懂请看lv博客(地址:http://blog.csdn.net/a409082492

第一次在航电上上榜不容易:并没有进过第一页
这里写图片描述

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int mod = 1000000007;
const int maxn=1000010;
typedef long long ll;
char str[maxn];//原字符串
char tmp[maxn<<1];//转换后的字符串
int Len[maxn<<1];
int sl;
//转换原始串
inline int INIT(char *st)
{
    int i,len=strlen(st);
    sl = len;
    tmp[0]='@';//字符串开头增加一个特殊字符,防止越界
    for(i=1;i<=2*len;i+=2)
    {
        tmp[i]='#';
        tmp[i+1]=st[i/2];
    }
    tmp[2*len+1]='#';
    tmp[2*len+2]='$';//字符串结尾加一个字符,防止越界
    tmp[2*len+3]=0;
    return 2*len+1;//返回转换字符串的长度
}
//Manacher算法计算过程
inline int MANACHER(char *st,int len)
{
     int mx=0,ans=0,po=0;//mx即为当前计算回文串最右边字符的最大值
     for(int i=1;i<=len;i++)
     {
         if(mx>i)
         Len[i]=min(mx-i,Len[2*po-i]);//在Len[j]和mx-i中取个小
         else
         Len[i]=1;//如果i>=mx,要从头开始匹配
         while(st[i-Len[i]]==st[i+Len[i]])
         Len[i]++;
         if(Len[i]+i>mx)//若新计算的回文串右端点位置大于mx,要更新po和mx的值
         {
             mx=Len[i]+i;
             po=i;
         }
         ans=max(ans,Len[i]);
     }
     return ans-1;//返回Len[i]中的最大值-1即为原串的最长回文子串额长度
}

const int SIZE = maxn << 1;

int C1[SIZE], C2[SIZE], C3[SIZE], C4[SIZE];


inline void modify1(int l,int r,int v)
{
   // printf("l=%d r=%d v=%d\n",l,r,v);
    if(l > r) return;
    C1[l] += v;
    C1[l] %= mod;
    C1[r+1] -= v;
    C1[r+1] %= mod;
}

inline void modify2(int l,int r,int v)
{
    if(l > r) return;
    C2[l] += v;
    C2[l] %= mod;
    C2[r+1] -= v;
    C2[r+1] %= mod;
}

inline void modify3(int l,int r,int v)
{
    if(l > r) return;
    C3[l] += v;
    C3[l] %= mod;
    C3[r+1] -= v;
    C3[r+1] %= mod;
}

inline void modify4(int l,int r,int v)
{
    if(l > r) return;
    C4[l] += v;
    C4[l] %= mod;
    C4[r+1] -= v;
    C4[r+1] %= mod;
}


inline void init()
{
    memset(C1,0,sizeof(C1));
    memset(C2,0,sizeof(C2));
    memset(C3,0,sizeof(C3));
    memset(C4,0,sizeof(C4));
}

int main() {
    while(~scanf("%s",str)) {
        int l = INIT(str);
        MANACHER(tmp, l);
        init();
        int res = 0;
        for(int i = l; i >= 1; i--) {
            modify1((i-Len[i]+1),i,i);
            modify3((i-Len[i]+1),i,1);
        }
        for(int i = 1; i <= l; i++) {
            modify2(i,(i+Len[i]-1),i);
            modify4(i,(i+Len[i]-1),1);
        }
        for(int i = 1; i <= l; i++) C1[i] += C1[i-1], C1[i] =(mod+C1[i])%mod;
        for(int i = 1; i <= l; i++) C2[i] += C2[i-1], C2[i] =(mod+C2[i])%mod;
        for(int i = 1; i <= l; i++) C3[i] += C3[i-1], C3[i] =(mod+C3[i])%mod;
        for(int i = 1; i <= l; i++) C4[i] += C4[i-1], C4[i] =(mod+C4[i])%mod;
        for(int i = 2,j = 0; i < l-1; i+=2,j++) {
            int lt = ((C1[i+2] - (ll)C3[i+2]*((i+2)/2))%mod + mod) % mod;
            int rt = ((C2[i] - (ll)C4[i]*(i/2))%mod + mod ) % mod;
            res += ((ll)lt * (ll)rt) %mod;
            res %= mod;
        }
        printf("%d\n",res);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值