zoukankan      html  css  js  c++  java
  • HDU5658 CA Loves Palindromic(回文树)

    描述

    传送门:我是传送门

    CA loves strings, especially loves the palindrome strings. One day he gets a string, he wants to know how many palindromic substrings in the substring S[l,r]S[l,r]. Attantion, each same palindromic substring can only be counted once.

    输入

    First line contains TT denoting the number of testcases. TT testcases follow. For each testcase: First line contains a string SS. We ensure that it is contains only with lower case letters. Second line contains a interger QQ, denoting the number of queries. Then QQ lines follow, In each line there are two intergers l,rl,r, denoting the substring which is queried. 1T101≤T≤10, 1length1000,1Q100000,1lrlength1≤length≤1000,1≤Q≤100000,1≤l≤r≤length

    输出

    For each testcase, output the answer in QQ lines.

    样例

    输入

    1
    abba
    2
    1 2
    1 3

    输出

    2
    3

    Note

    In first query, the palindromic substrings in the substring S[1,2]S[1,2] are “a”,”b”.
    In second query, the palindromic substrings in the substring S[1,2]S[1,2] are “a”,”b”,”bb”.
    Note that the substring “b” appears twice, but only be counted once.
    You may need an input-output optimization.

    思路

    利用回文树的性质暴力预处理所有子串

    每次查询都是0(1)0(1)的复杂度

    =P2不同回文子串的数量=P−2

    代码

      1 /*
      2  * =========================================================================
      3  *
      4  *       Filename:  C.cpp
      5  *
      6  *           Link:  http://acm.hdu.edu.cn/showproblem.php?pid=5658
      7  *
      8  *        Version:  1.0
      9  *        Created:  2018/09/03 04时11分41秒
     10  *       Revision:  none
     11  *       Compiler:  g++
     12  *
     13  *         Author:  杜宁元 (https://duny31030.top/), duny31030@126.com
     14  *   Organization:  QLU_浪在ACM
     15  *
     16  * =========================================================================
     17  */
     18 #include <bits/stdc++.h>
     19 using namespace std;
     20 #define clr(a, x) memset(a, x, sizeof(a))
     21 #define rep(i,a,n) for(int i=a;i<=n;i++)
     22 #define pre(i,a,n) for(int i=a;i>=n;i--)
     23 #define ll long long
     24 #define max3(a,b,c) fmax(a,fmax(b,c))
     25 #define ios ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
     26 const double eps = 1e-6;
     27 const int INF = 0x3f3f3f3f;
     28 const int mod = 1e9 + 7;
     29 const int MAXN = 1e5+10;
     30 const int N = 26;
     31 char s[MAXN];
     32 struct node
     33 {
     34     int next[N];   // next指针,next指针和字典树类似,指向的串为
     35                    // 当前穿两端加上同一个字符构成
     36     int fail;      // fail指针,失配后跳转到fail指针指向的节点
     37     int cnt;       // 表示节点i的本质不同的串的个数
     38                    // 建树时求出的不是完全的,最后Count()函数跑一遍以后才是正确的
     39     int num;       // 表示以节点i表示的最长回文串的最右端点为回文串结尾的回文个数
     40     int len;       // 表示以当前节点表示的最长回文串长度(一个节点表示一个回文串)
     41     int S;         // 存放添加的字符
     42 }pam[MAXN];
     43 int last;   // 指向新添加一个字母后所形成的最长回文串表示的节点
     44 int n;      // 表示添加的字符个数
     45 int p;      // 表示添加的节点个数
     46 
     47 int newnode(int x)
     48 {
     49     for(int i = 0;i < N;i++)
     50         pam[p].next[i] = 0;
     51     pam[p].cnt = 0;
     52     pam[p].num = 0;
     53     pam[p].len = x;
     54     return p++;
     55 }
     56 
     57 void Init()
     58 {
     59     p = 0;
     60     newnode(0);
     61     newnode(-1);
     62     last = 0;
     63     n = 0;
     64     pam[n].S = -1;   // 开头存放一个字符集中没有的字符,减少特判
     65     pam[0].fail = 1;
     66 }
     67 
     68 int get_fail(int x)
     69 {
     70     while(pam[n-pam[x].len-1].S != pam[n].S)
     71         x = pam[x].fail;
     72     return x;
     73 }
     74 
     75 void Add(int c)
     76 {
     77     c -= 'a';
     78     pam[++n].S = c;
     79     int cur = get_fail(last);   // 通过上一个回文串找这个回文串的匹配位置
     80     if(!pam[cur].next[c])       // 如果这个回文串没有出现过,说明出现了
     81                                 // 一个新的本子不同的回文串
     82     {
     83         int now = newnode(pam[cur].len+2);   // 新建节点
     84         pam[now].fail = pam[get_fail(pam[cur].fail)].next[c];   
     85         // 和AC自动机一样建立fil指针,以便失败后回跳
     86         pam[cur].next[c] = now;
     87         pam[now].num = pam[pam[now].fail].num+1;
     88     }
     89     last = pam[cur].next[c];
     90     pam[last].cnt++;
     91 }
     92 
     93 void Count()
     94 {
     95     for(int i = p-1;i >= 0;--i)
     96     {
     97         pam[pam[i].fail].cnt += pam[i].cnt;
     98         // 父亲累加儿子才cnt,因为如果fail[v] = u , 则u一定是v的子回文串
     99     }
    100 }
    101 int T,que,l,r;
    102 int main()
    103 {
    104     ios
    105 #ifdef ONLINE_JUDGE 
    106 #else 
    107         freopen("in.txt","r",stdin);
    108     // freopen("out.txt","w",stdout); 
    109 #endif
    110     int pr[1010][1010];
    111     memset(pr,0,sizeof pr);
    112     scanf("%d",&T);
    113     while(T--)
    114     {
    115         scanf("%s",s);
    116         int len = strlen(s);
    117         for(int i = 0;i < len;i++)
    118         {
    119             Init();
    120             for(int j = i;j < len;j++)
    121             {
    122                 Add(s[j]);
    123                 pr[i][j] = p-2;
    124             }
    125         }
    126         scanf("%d",&que);
    127         while(que--)
    128         {
    129             scanf("%d %d",&l,&r);
    130             printf("%d
    ",pr[l-1][r-1]);
    131         }
    132     }
    133     fclose(stdin);
    134     // fclose(stdout);
    135     return 0;
    136 }
  • 相关阅读:
    Android组件化和插件化开发
    开发一流的 Android SDK:Fabric SDK 的创建经验
    关系 和非关系 阻塞非阻塞的区别
    AJAX 中JSON 和JSONP 的区别 以及请求原理
    九马画山数命运, 一身伴君不羡仙! 与代码不离不弃!
    移动端 transitionEnd函数用来检测过渡是否完成
    2017前端该学的知识 分享墨白的文章、大家共勉!
    移动端和pc端事件绑定方式以及取消浏览器默认样式和取消冒泡
    今天要带来的是移动端开发的基础内容
    离线存储
  • 原文地址:https://www.cnblogs.com/duny31030/p/14304935.html
Copyright © 2011-2022 走看看