• ECNUOJ 2619 询问


    询问

    Time Limit:2000MS Memory Limit:65536KB
    Total Submit:286 Accepted:70

    Description 

    Pollux最近对字符串匹配很感兴趣,他渐渐发现一个有趣的函数,并且他觉得利用这个函数或许可以建立一种新的匹配算法:
    对于字符串S[1…n]和i∈[1 , n] ,定义F(i) 为S 和 S[1…i] 的最长公共后缀的长度.
    例如对于串S[1…11] = zaaxbaacbaa ,则F(1) = 0 ,F(2) = 1 , F(3) = 2( 注意S[1…3] = zaa ) ,F(4) = 0 , …… F(10) = 1 ,F(11) = 11 ;
    对于串S[1…n],i∈[1 , n] ,S[i…n] 为S的后缀;
    但是有一点让他犯难的地方就是他不知道如何快速的计算这个函数在i∈[1 , n]的值,作为ECNU的一名编程高手,你能帮助他解决这个问题吗?

    Input 

    第一行为一个整数T,表示测数数据的组数.
    对于每组数据:
    第一行为一个字符串S,只由小写字母组成,如果len(s)表示s的长度,那么1 <= len(s) <= 1000000 ;
    接下来一个数N( 1 <= N <= 100000 ),表示询问的次数;
    接下来N行,每行一个数x( 1<=x<=len(s))。

    Output 

    对于每个x输出F(x);

    Sample Input 

    1
    zaaxbaacbaa
    11
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    Sample Output 

    0
    1
    2
    0
    0
    1
    3
    0
    0
    1
    11

    Source

    解题:没想到别的什么办法,只好用后缀数组了

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int maxn = 100010;
     4 char s[maxn];
     5 int sa[maxn],t[maxn],t2[maxn];
     6 int height[maxn],rk[maxn],c[maxn],n;
     7 void build_sa(int m) {
     8     int i,*x = t,*y = t2;
     9     for(i = 0; i < m; ++i) c[i] = 0;
    10     for(i = 0; i < n; ++i) c[x[i] = s[i]]++;
    11     for(i = 1; i < m; ++i) c[i] += c[i-1];
    12     for(i = n-1; i >= 0; --i) sa[--c[x[i]]] = i;
    13 
    14     for(int k = 1; k <= n; k <<= 1) {
    15         int p = 0;
    16         for(i = n-k; i < n; ++i) y[p++] = i;
    17         for(i = 0; i < n; ++i)
    18             if(sa[i] >= k) y[p++] = sa[i] - k;
    19         for(i = 0; i < m; ++i) c[i] = 0;
    20         for(i = 0; i < n; ++i) c[x[y[i]]]++;
    21         for(i = 1; i < m; ++i) c[i] += c[i-1];
    22         for(i = n-1; i >= 0; --i) sa[--c[x[y[i]]]] = y[i];
    23         swap(x,y);
    24         x[sa[0]] = 0;
    25         for(p = i = 1; i < n; ++i)
    26             x[sa[i]] = y[sa[i]] == y[sa[i-1]] && y[sa[i]+k] == y[sa[i-1]+k]?p-1:p++;
    27         if(p >= n) break;
    28         m = p;
    29     }
    30 }
    31 void getHeight() {
    32     int i,j,k = 0;
    33     for(i = 0; i < n; ++i) rk[sa[i]] = i;
    34     for(i = 0; i < n; ++i) {
    35         if(k) --k;
    36         j = sa[rk[i]-1];
    37         while(i + k < n && j + k < n && s[i+k] == s[j+k]) ++k;
    38         height[rk[i]] = k;
    39     }
    40 }
    41 int st[maxn][20],m;
    42 void initRMQ() {
    43     memset(st,0,sizeof st);
    44     for(int i = 1; i < n; ++i) st[i][0] = height[i];
    45     for(int i = 1; (1<<i) < n; ++i)
    46         for(int j = 1; j + (1<<i) <= n; ++j)
    47             st[j][i] = min(st[j][i-1],st[j+(1<<(i-1))][i-1]);
    48 }
    49 int query(int s,int t) {
    50     if(s == t) return n - 1 - s;
    51     s = rk[s];
    52     t = rk[t];
    53     if(s > t) swap(s,t);
    54     s++;
    55     int k = log2(t - s + 1);
    56     return min(st[s][k],st[t-(1<<k)+1][k]);
    57 }
    58 int main() {
    59     int kase;
    60     scanf("%d",&kase);
    61     while(kase--) {
    62         scanf("%s",s);
    63         n = strlen(s)+1;
    64         reverse(s,s+n-1);
    65         build_sa(256);
    66         getHeight();
    67         initRMQ();
    68         scanf("%d",&m);
    69         while(m--) {
    70             int tmp;
    71             scanf("%d",&tmp);
    72             printf("%d
    ",query(0,n - 1 - tmp));
    73         }
    74     }
    75     return 0;
    76 }
    View Code
  • 相关阅读:
    Windows 环境 cygwin 安装 SSH
    看见上帝的 10 个公式……
    移动平均
    分位数
    算术平均、几何平均、调和平均、平方平均和移动平均
    平均数、中位数和众数及它们之间的关系
    10 个超炫绘制图表图形的 Javascript 插件【转载+整理】
    “服务器推”技术【转载+整理】
    网站数据监控监测系统
    Active Directory 域服务(AD DS)
  • 原文地址:https://www.cnblogs.com/crackpotisback/p/4630342.html
Copyright © 2020-2023  润新知