hdu 3948 后缀数组

The Number of Palindromes

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 2465    Accepted Submission(s): 841

Problem Description

Now, you are given a string S. We want to know how many distinct substring of S which is palindrome.

Input

The first line of the input contains a single integer T(T<=20), which indicates number of test cases.
Each test case consists of a string S, whose length is less than 100000 and only contains lowercase letters.

Output

For every test case, you should output "Case #k:" first in a single line, where k indicates the case number and starts at 1. Then output the number of distinct substring of S which is palindrome.

Sample Input

3

aaaa

abab

abcd

Sample Output

Case #1: 4

Case #2: 4

Case #3: 4

/*
hdu 3948 后缀数组

problem:
给你一个字符串,问其中不同回文子串的个数

solve:
通过长度的奇偶性能够找出所有的回文子串(类似求最长回文子串),但是其中有很多重复的一直不知道怎么处理
有的较短的回文子串包含在一个长的里面,有的是两个回文有重复的部分。
最开始尝试的是通过枚举字符串所有的位置,类似于manacher求出所有位置的回文长度.但是发现完全没法解决重复的问题

参考别人的方法:
首先height数组可以知道两个回文子串的关系,所以枚举height.
通过ta记录当前位置与上一个回文串的公共前缀,当遇到下个回文串就能知道两个回文串的公共部分.即需要减去的重复部分
ta = min(ta,height[i]);
而且枚举height不知道当前回文串是否处理过,所以用vis记录一下

hhh-2016-08-11 13:51:03
*/
#include <iostream>
#include <vector>
#include <cstring>
#include <string>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <functional>
#include <map>
using namespace std;
#define lson  (i<<1)
#define rson  ((i<<1)|1)
typedef long long ll;
typedef unsigned int ul;
const int INF = 0x3f3f3f3f;
const int  maxn = 200000+10;
const int mod = 1e9+7;

int t1[maxn],t2[maxn],c[maxn];
bool cmp(int *r,int a,int b,int l)
{
    return r[a]==r[b] &&r[l+a] == r[l+b];
}

void get_sa(int str[],int sa[],int Rank[],int height[],int n,int m)
{
    n++;
    int p,*x=t1,*y=t2;
    for(int i = 0; i < m; i++) c[i] = 0;
    for(int i = 0; i < n; i++) c[x[i] = str[i]]++;
    for(int i = 1; i < m; i++) c[i] += c[i-1];
    for(int i = n-1; i>=0; i--) sa[--c[x[i]]] = i;
    for(int j = 1; j <= n; j <<= 1)
    {
        p = 0;
        for(int i = n-j; i < n; i++) y[p++] = i;
        for(int i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i]-j;
        for(int i = 0; i < m; i++) c[i] = 0;
        for(int i = 0; i < n; i++) c[x[y[i]]]++ ;
        for(int i = 1; i < m; i++) c[i] += c[i-1];
        for(int i = n-1; i >= 0; i--)  sa[--c[x[y[i]]]] = y[i];

        swap(x,y);
        p = 1;
        x[sa[0]] = 0;
        for(int i = 1; i < n; i++)
            x[sa[i]] = cmp(y,sa[i-1],sa[i],j)? p-1:p++;
        if(p >= n) break;
        m = p;
    }
    int k = 0;
    n--;
    for(int i = 0; i <= n; i++)
        Rank[sa[i]] = i;
    for(int i = 0; i < n; i++)
    {
        if(k) k--;
        int j = sa[Rank[i]-1];
        while(str[i+k] == str[j+k]) k++;
        height[Rank[i]] = k;
    }

}

int mm[maxn];
int dp[20][maxn];

int Rank[maxn],height[maxn];
int sa[maxn];
char str[maxn];
int r[maxn];

void ini_RMQ(int n)
{
    mm[0] = -1;
    for(int i = 1; i <= n; i++)
        mm[i] = (((i & (i-1)) == 0) ? mm[i-1]+1:mm[i-1]);

    for(int i =1; i <= n; i++)
        dp[0][i] = height[i];
    for(int i = 1; i <= mm[n]; i++)
    {
        for(int j = 1; j+(1<<i)-1 <= n; j++)
        {
            int a = dp[i-1][j];
            int b = dp[i-1][j+(1<<(i-1))];
            dp[i][j] = min(a,b);
        }
    }
}

int askRMQ(int a,int b)
{
    int t = mm[b-a+1];
    b -= (1<<t)-1;
    return min(dp[t][a],dp[t][b]);
}

int fin(int a,int b)
{
    a = Rank[a],b = Rank[b];
    if(a > b) swap(a,b);
    return askRMQ(a+1,b);
}
int vis[maxn];

int main()
{
    int T;
    int cas = 1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%s",str);
        int len = strlen(str);
        for(int i= 0; i < len; i++)
            r[i] = str[i];
        r[len] = 1;
        for(int i = 0; i < len; i++)
            r[len+1+i] = str[len-1-i];
        r[2*len+1] = 0;
        get_sa(r,sa,Rank,height,len*2+1,128);
        ini_RMQ(2*len+1);
        int ans = 0;
        int n = len+len+1;
        int ta=0;
        memset(vis,0,sizeof(vis));
        for(int i = 2; i <= n; i++)
        {
            ta = min(height[i],ta);
            if(!sa[i])
                continue;
            if(vis[n-sa[i]])
            {
                int t = fin(sa[i],n-sa[i]);
                if(t > ta)
                {
                    ans += t-ta;
                    ta = t;
                }
            }
            else
                vis[sa[i]] = 1;
        }
        ta= 0 ;
        memset(vis,0,sizeof(vis));
        for(int i = 2; i <= n; i++)
        {
            ta= min(ta,height[i]);
            if(vis[n-sa[i]-1])
            {
                int t = fin(sa[i],n-sa[i]-1);
                if(t > ta)
                {
                    ans += t-ta;
                    ta = t;
                }
            }
            else
                vis[sa[i]] = 1;
        }
        printf("Case #%d: ",cas++);
        printf("%d\n",ans);
    }
}

  

时间: 2024-10-30 00:47:50

hdu 3948 后缀数组的相关文章

HDU - 3948 后缀数组+Manacher

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3948 题意:给定一个字符串,求字符串本质不同的回文子串个数. 思路:主要参考该篇解题报告 先按照manacher的构造方法改造一遍串,然后跑一遍manacher.求出以i为中心的最长回文串长度p[i]. 然后跑一遍后缀数组,若已经求得后缀sa[i-1]对答案的贡献,然后现在计算后缀sa[i],本来是要加上以sa[i]为中心的回文串的个数p[sa[i]]. 我们可以维护一个tmp,也就是上图中蓝色的框

hdu 3518 后缀数组

Boring counting Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 2906    Accepted Submission(s): 1201 Problem Description 035 now faced a tough problem,his english teacher gives him a string,whic

Hdu 1403(后缀数组)

题目链接 Longest Common Substring Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 4077    Accepted Submission(s): 1544 Problem Description Given two strings, you have to tell the length of the Longe

HDU 6194 后缀数组

题意:求出现恰好 k次的子串(可以重叠)的个数: 分析: 刚开始想到了是后缀数组,但是有什么性质,具体怎么做的没有想到.回到主题来: 连续 k 次,说明这 k 个后缀排序后在一起,每次枚举 长度的为 k 的区间,用RMQ算出最长公共前缀长度,这里就有 len 个子串是 符合满足 k 次的,但是又有可能过短而不止出现了 k次,那么有多少呢? 那么就是 a 不属于,len - height[j+1],前面也一样.也就是每次只算他独有的子串,但是你可能问 len > k 的时候,可以从新组成一组子串!

HDU - 1403 后缀数组初步

题意:求两个串的最长公共子串 两个串连接起来然后求高度数组 注意两个sa值必须分别在不同一侧 本题是用来测试模板的,回想起青岛那次翻车感觉很糟糕 #include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<string> #include<vec

hdu 5030 Rabbit&#39;s String(后缀数组&amp;二分)

Rabbit's String Time Limit: 40000/20000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 288    Accepted Submission(s): 108 Problem Description Long long ago, there lived a lot of rabbits in the forest. One day, the

HDU 5769 Substring(后缀数组)

[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5769 [题目大意] 在一个串中求出包含字母的子串个数, 只要存在一个字符不相等的子串即可视为不同的子串. [题解] 因为要求存在字符不相等因此我们可以利用后缀数组统计, 后缀数组的h数组可以记录前后两个后缀的最长公共前缀这样子相同的前缀就不会被多次计算, 保存每个位置之后出现的最近的要求的字母的位置, 从该后缀的包含该字母的位置往后且不在最长公共前缀的范围内的位置都可以作为子串的右端点, 统计左

hdu 5769 Substring 后缀数组 + KMP

http://acm.hdu.edu.cn/showproblem.php?pid=5769 题意:在S串中找出X串出现的不同子串的数目? 其中1 官方题解: 处理出后缀数组中的sa[]数组和height[]数组.在不考虑包含字符X的情况下,不同子串的个数为 如果要求字符X,只需要记录距离sa[i]最近的字符X的位置(用nxt[sa[i]]表示)即可,个数 理解:后缀数组height[i]就是sa[i]与sa[i-1]的LCP,在后缀数组中求解全部的不同子串(之前只写过SAM处理所有不同子串..

hdu 5008(2014 ACM/ICPC Asia Regional Xi&#39;an Online ) Boring String Problem(后缀数组&amp;二分)

Boring String Problem Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 219    Accepted Submission(s): 45 Problem Description In this problem, you are given a string s and q queries. For each que