首页 > 其他分享 >hdu 5157(manacher+前缀和+树状数组)

hdu 5157(manacher+前缀和+树状数组)

时间:2023-05-29 18:31:42浏览次数:63  
标签:hdu 200005 int manacher s1 5157 merg id 回文


题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5157

解题思路:

我们可以先用mancher算法对字符串进行处理,把以每个点为中心的回文串半径求出来,然后进行处理。

加入对以p为中心的点,从p-r[i]+1~p都是回文串的开头,那么对于每个回文串(开头是j)只要记录结尾从1~j-1的回文串个数,我们可以用dp记录以每个点为结尾的回文串个数,s[i]=sigma(dp[i]),则是结尾从1~j-1的回文串个数。那么对这个中心点来说一共的回文串对应该有:s[p-r[i]]+...+s[p-1]个,那么我们可以继续用一个数组s1[i]求s[i]的前缀和,那么总复杂度是O(n)。

至于dp[i]怎么求,你已经知道了半径,那从p~p+r[i]-1这些点的dp值都要加1,可以用树状数组来维护。


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

typedef long long LL;
char c[200005],f[100005];
int r[200005],tree[200005];
LL s[200005],s1[200005];

int low(int n)
{
	return n & -n;
}

void merg(int p,int n,int k)
{
    while(p<=n)
	{
       tree[p]+=k;
        p=p+low(p);
    }
}

int sum(int p)
{
    int s=0;
    while(p>0)
	{
        s+=tree[p];
        p=p-low(p);
    }
    return s;
}

void mancher(int n)
{
    int id;
    r[0]=1;
    id=0;
    for(int i=1; i<=2*n; i++)
	{
        if(r[id]+id > i) r[i] = min(r[2*id-i],r[id]+id-i);
		else r[i] = 1;
        while(i-r[i]>=0 && i+r[i]<=2*n && c[i-r[i]]==c[i+r[i]]) r[i]++;
        if(i+r[i] > id+r[id])
            id=i;
    }
}

void get_back(int n)
{
    memset(tree,0,sizeof(tree));
    for(int i=1;i<=2*n;i++)
	{
        int p=i+r[i]-1;
        if(i%2==0)
		{
            if(p>i)
			{
                merg(i/2+1,n,1);
                merg(p/2+1,n,-1);
            }
        }
        else
		{
			merg((i+1)/2,n,1);
			merg(p/2+1,n,-1);
        }
    }
    s[0]=0;
    s1[0]=0;
    for(int i=1;i<=n;i++)
	{
        s[i]=s[i-1]+sum(i);
        s1[i]=s1[i-1]+s[i];
    }
}

void work(int n)
{
    LL ans=0;
    int i,j;
    for(i=1;i<=2*n;i++)
	{
        if(i % 2 == 0 && r[i] > 1)
			ans+=s1[i/2-1]-s1[(i-r[i]+1)/2-1];
        else if(i % 2 == 1)
            ans+=s1[(i+1)/2-1]-s1[(i-r[i]+1)/2-1];
    }
    cout << ans << endl;
}

int main()
{
    int i,j,n;
    while(scanf("%s",f)!=EOF)
	{
        n = strlen(f);
        c[0] = '#';
        for(i=1;i<=n;i++)
		{
            c[2*i] = '#';
            c[2*i-1] = f[i-1];
        }
        mancher(n);
        get_back(n);
        work(n);
    }
	return 0;
}




标签:hdu,200005,int,manacher,s1,5157,merg,id,回文
From: https://blog.51cto.com/u_16143128/6373505

相关文章

  • hdu:第K小的数(构造二分)
    ProblemDescription给定\(n\)个正整数\(a_1,a_2,\dots,a_n\)和\(m\)个正整数\(b_1,b_2,\dots,b_m\)。请在\(n\timesm\)个\(a_i+b_j(1\leqi\leqn,1\leqj\leqm)\)中,找到第\(k\)小的数(不去重)。Input第一行包含一个正整数\(T(1\leqT\leq10)\),表示测试数据的组数。每组......
  • hdu:Ice Cream Tower(构造二分)
    一座高度为k的塔\(b1,b_2,\dots,b_k\)满足\(2b_1\leqb_2,2b_2\leqb_3,2b_3\leqb_4,\dots,2b{k-1}\leqb_k\)你要从中选择一些数来叠很多座高度为\(k\)的塔,问最多能叠多少座塔。Input第一行包含一个正整数T(1≤T≤10),表示测试数据的组数。每组数据第一行包含两个正整数n,k(2......
  • hdu:序列划分(构造二分)
    ProblemDescription给定\(n\)个正整数\(a_1,a_2,\dots,a_n\),将这个序列从左到右划分成\(m\)段,使得每段至少有一个数。你需要让数字之和最大的那一段的数字和尽可能得小。Input第一行包含一个正整数T(1≤T≤10),表示测试数据的组数。每组数据第一行包含两个正整数n,m(1≤m≤......
  • HDU 1176 免费馅饼(简单动态规划)
    传送门这道题是中文描述的,我相信大家都肯定能够看得懂(滑稽),思路上呢大概就是一个升级版的数塔(点我去看数塔)既然是动态规划问题所以首先肯定要先找出来状态转移方程,我找到的状态转移方程就是a[i][j]+=max(max(a[i+1][j+1],a[i+1][j]),a[i+1][j-1]),其中a[i][j]就是表示第i时刻在k位......
  • HDU 1029 Ignatius and the Princess IV(基础dp)
    传送门题目大意就是给你n个数(保证n为一个奇数),存在一个数出现的次数大于(n+1)/2次,求这个数;这个数出现的次数比其他数出现的次数加起来还多,那么当这个数出现时+1,其他的数出现时-1,最后得到的数为正数。假定一个数为特殊数,若当前数与特殊数相同则cnt++,若不相同则cnt--,如果这时cnt<0,用当......
  • HDU 2084 数塔(动态规划入门)
    传送门中文题就不给大家翻译了(手动滑稽),反正大家都看得懂。这是一道动态规划入门的题目,只需要找出状态转移方程即可。状态方程:dp[i][j]=a[i][j]+max(dp[i+1][j],dp[i+1][j])(dp[i][j]表示从第i层第j个数开始搜能得到的最大数)代码如下:#include<cstring>#include<iostream>#include<......
  • HDU 1024 Max Sum Plus Plus(动态规划)
    传送门题意是给你个数字序列,现在让你把这个序列分成m个连续的子序列,且要求这m个子序列的累加和最大。思路:这道题的题意可以理解为问在序列为末尾时,把序列分为m个子序列这个状态时的最大累加和,那么可以得出这个状态应该是由上一个状态转移得来:(因为dp[i][j]表示数到第j个字符时,前j个......
  • hdu 4758 Walk Through Squares(AC自动机+DP,4级)
    WalkThroughSquaresTimeLimit:4000/2000MS(Java/Others)    MemoryLimit:65535/65535K(Java/Others)TotalSubmission(s):234    AcceptedSubmission(s):58ProblemDescription  Onthebeamingdayof60thanniversaryofNJUST,asamilitary......
  • HDU-1003- Max Sum (动态规划)
    MaxSumTimeLimit:2000/1000MS(Java/Others)    MemoryLimit:65536/32768K(Java/Others)TotalSubmission(s):192050    AcceptedSubmission(s):44727ProblemDescriptionGivenasequencea[1],a[2],a[3]......a[n],yourjobistocalculatethe......
  • hdu-2680-Choose the best route(dijkstra)
    ChoosethebestrouteTimeLimit:2000/1000MS(Java/Others)    MemoryLimit:32768/32768K(Java/Others)TotalSubmission(s):10470    AcceptedSubmission(s):3367ProblemDescriptionOneday,Kikiwantstovisitoneofherfriends.Assheis......