HDU 4691

http://acm.hdu.edu.cn/showproblem.php?pid=4691

留个板子。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <algorithm>
  4 #include <cstring>
  5 #include <cmath>
  6 using namespace std;
  7 const int maxn = 1e5+5;
  8 int t1[maxn],t2[maxn],c[maxn];//求SA数组需要的中间变量,不需要赋值
  9 //待排序的字符串放在s数组中,从s[0]到s[n-1],长度为n,且最大值小于m,
 10 //除s[n-1]外的所有s[i]都大于0,r[n-1]=0
 11 //函数结束以后结果放在sa数组中
 12 bool cmp(int *r,int a,int b,int l)
 13 {
 14     return r[a] == r[b] && r[a+l] == r[b+l];
 15 }
 16 void da(int str[],int sa[],int Rank[],int height[],int n,int m)
 17 {
 18     n++;
 19     int i, j, p, *x = t1, *y = t2;
 20     //第一轮基数排序,如果s的最大值很大,可改为快速排序
 21     for(i = 0;i < m;i++)c[i] = 0;
 22     for(i = 0;i < n;i++)c[x[i] = str[i]]++;
 23     for(i = 1;i < m;i++)c[i] += c[i-1];
 24     for(i = n-1;i >= 0;i--)sa[--c[x[i]]] = i;
 25     for(j = 1;j <= n; j <<= 1)
 26     {
 27         p = 0;
 28         //直接利用sa数组排序第二关键字
 29         for(i = n-j; i < n; i++)y[p++] = i;//后面的j个数第二关键字为空的最小
 30         for(i = 0; i < n; i++)if(sa[i] >= j)y[p++] = sa[i] - j;
 31         //这样数组y保存的就是按照第二关键字排序的结果
 32         //基数排序第一关键字
 33         for(i = 0; i < m; i++)c[i] = 0;
 34         for(i = 0; i < n; i++)c[x[y[i]]]++;
 35         for(i = 1; i < m;i++)c[i] += c[i-1];
 36         for(i = n-1; i >= 0;i--)sa[--c[x[y[i]]]] = y[i];
 37         //根据sa和x数组计算新的x数组
 38         swap(x,y);
 39         p = 1; x[sa[0]] = 0;
 40         for(i = 1;i < n;i++)
 41             x[sa[i]] = cmp(y,sa[i-1],sa[i],j)?p-1:p++;
 42         if(p >= n)break;
 43         m = p;//下次基数排序的最大值
 44     }
 45     int k = 0;
 46     n--;
 47     for(i = 0;i <= n;i++)Rank[sa[i]] = i;
 48     for(i = 0;i < n;i++)
 49     {
 50         if(k)k--;
 51         j = sa[Rank[i]-1];
 52         while(str[i+k] == str[j+k])k++;
 53         height[Rank[i]] = k;
 54     }
 55 }
 56 int Rank[maxn],height[maxn];
 57 int sa[maxn];
 58 char s[maxn];
 59 int M[maxn][20];
 60 int r[maxn];
 61 int A[maxn],B[maxn];
 62 void RMQ(int n)
 63 {
 64     for(int i=1;i<=n;i++) M[i][0] = height[i];
 65     for(int j=1;(1<<j)<=n;j++)
 66     {
 67         for(int i=1;(i+(1<<j)-1)<=n;i++)
 68         {
 69             M[i][j] = min(M[i][j-1],M[i+(1<<(j-1))][j-1]);
 70         }
 71     }
 72 }
 73 int ST(int l,int r)
 74 {
 75     int k = 0;
 76     while((1<<(k+1))<=(r-l+1)) k++;
 77     return min(M[l][k],M[r-(1<<k)+1][k]);
 78 }
 79 int lcp(int a,int b)
 80 {
 81     a = Rank[a],b = Rank[b];
 82     if(a>b) swap(a,b);
 83     return ST(a+1,b);
 84 }
 85 int cal(int x)
 86 {
 87     int res = 0;
 88     if(x==0) res++;
 89     while(x)
 90     {
 91         x /= 10;
 92         res++;
 93     }
 94     return res;
 95 }
 96 int main()
 97 {
 98     while(scanf("%s",s)!=EOF)
 99     {
100         int len = strlen(s);
101         for(int i=0;i<len;i++) r[i] = s[i];
102         r[len] = 0;
103         da(r,sa,Rank,height,len,128);
104         RMQ(len);
105         long long ans1 = 0,ans2 = 0;
106         int T;scanf("%d",&T);
107         for(int i=1;i<=T;i++)
108         {
109             scanf("%d %d",&A[i],&B[i]);
110             if(i==1)
111             {
112                 ans1 += B[i]-A[i]+1;
113                 ans2 += B[i]-A[i]+3;
114                 continue;
115             }
116             int temp = 0;
117             if(A[i]!=A[i-1]) temp = lcp(A[i-1],A[i]);
118             else temp = 1e9;
119             temp = min(temp,B[i]-A[i]);
120             temp = min(temp,B[i-1]-A[i-1]);
121             ans1 += B[i]-A[i]+1;
122             ans2 += B[i]-A[i]-temp+2;
123             ans2 += cal(temp);
124         }
125         printf("%I64d %I64d
",ans1,ans2);
126     }
127     return 0;
128 }
原文地址:https://www.cnblogs.com/littlepear/p/7339942.html