• poj 2406 Power Strings (kmp 中 next 数组的应用||后缀数组)


    http://poj.org/problem?id=2406

    Power Strings
    Time Limit: 3000MS   Memory Limit: 65536K
    Total Submissions: 27003   Accepted: 11311

    Description

    Given two strings a and b we define a*b to be their concatenation. For example, if a = "abc" and b = "def" then a*b = "abcdef". If we think of concatenation as multiplication, exponentiation by a non-negative integer is defined in the normal way: a^0 = "" (the empty string) and a^(n+1) = a*(a^n).

    Input

    Each test case is a line of input representing s, a string of printable characters. The length of s will be at least 1 and will not exceed 1 million characters. A line containing a period follows the last test case.

    Output

    For each s you should print the largest n such that s = a^n for some string a.

    Sample Input

    abcd
    aaaa
    ababab
    .
    

    Sample Output

    1
    4
    3

    思路:
    理解next数组,利用next数组进行巧妙求解
     1 #include<iostream>
     2 #include<string.h>
     3 #include<stdio.h>
     4 using namespace std;
     5 #define MAX 1000000
     6 
     7 void get_next(char *str,int *next)
     8 {
     9     int i=0,j=-1;
    10     int tlen=strlen(str);
    11     next[0]=-1;
    12     while(i<tlen)
    13     {
    14         if(j==-1||str[i]==str[j])
    15         {
    16             i++;
    17             j++;
    18             if(str[i]!=str[j])
    19                 next[i]=j;
    20             else
    21                 next[i]=next[j];
    22         }
    23         else
    24             j=next[j];
    25     }
    26 }
    27 char str[MAX+10];
    28 int next[MAX+10];
    29 int main()
    30 {
    31     int t=1;
    32     while(~scanf("%s",str))
    33     {
    34         if(str[0]=='.')  break;
    35         get_next(str,next);
    36         int len = strlen(str);
    37     //    for(int i=0;i<=len;i++)  cout<<next[i]<<" "; cout<<endl;
    38         if(len%(len-next[len])==0)  //next[len]为匹配到len时失配所要跳到的上一个匹配点,len-next[len]即为一个循环节
    39             printf("%d
    ",len/(len-next[len]));
    40         else
    41             printf("1
    ");
    42     }
    43     return 0;
    44 }

     (后缀数组)思路:

    给定一个字符串L,已知这个字符串是由某个字符串S重复R次而得到的,求R的最大值。

      算法分析:

      做法比较简单,穷举字符串S的长 k,然后判断是否满足。判断的时候,先看字符串L的长度能否被k整除,再看suffix(1)和suffix(k+1)的最长公共前缀是否等于n-k。在询问最长公共前缀的时候,suffix(1)是固定的,所以RMQ问题没有必要做所有的预处理,只需求出height数组中的每一个数到height[rank[1]]之间的最小值即可。整个做法的时间复杂度为O(n)。

    以下是我超时代码:(尼玛滴不科学呀!!!)

    TLE代码:跪求大神赐教!!!

      1 #include <iostream>
      2 #include <stdio.h>
      3 #include<string.h>
      4 
      5 using namespace std;
      6 
      7 #define maxn 1100000
      8 
      9 #define cls(x) memset(x, 0, sizeof(x))
     10 
     11 int wa[maxn],wb[maxn],wv[maxn],wss[maxn];
     12 
     13 int cmp(int *r,int a,int b,int l){return r[a]==r[b]&&r[a+l]==r[b+l];}
     14 
     15 //倍增算法
     16 void da(char *r,int *sa,int n,int m)
     17 {
     18      cls(wa);
     19      cls(wb);
     20      cls(wv);
     21      int i,j,p,*x=wa,*y=wb,*t;
     22 
     23      //基数排序
     24      for(i=0;i<m;i++) wss[i]=0;
     25      for(i=0;i<n;i++) wss[x[i]=r[i]]++;
     26      for(i=1;i<m;i++) wss[i]+=wss[i-1];
     27      for(i=n-1;i>=0;i--) sa[--wss[x[i]]]=i;
     28 
     29      // 在第一次排序以后,rank数组中的最大值小于p,所以让m=p。整个倍增算法基本写好,代码大约25行。
     30      for(j=1,p=1;p<n;j*=2,m=p)
     31      {
     32        //接下来进行若干次基数排序,在实现的时候,这里有一个小优化。基数排序要分两次,第一次是对第二关键字排序,第二次是对第一关键字排序。对第二关键字排序的结果实际上可以利用上一次求得的sa直接算出,没有必要再算一次
     33        for(p=0,i=n-j;i<n;i++) y[p++]=i;
     34        for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
     35 
     36        //其中变量j是当前字符串的长度,数组y保存的是对第二关键字排序的结果。然后要对第一关键字进行排序,
     37        for(i=0;i<n;i++) wv[i]=x[y[i]];
     38        for(i=0;i<m;i++) wss[i]=0;
     39        for(i=0;i<n;i++) wss[wv[i]]++;
     40        for(i=1;i<m;i++) wss[i]+=wss[i-1];
     41        for(i=n-1;i>=0;i--) sa[--wss[wv[i]]]=y[i];
     42 
     43        //这样便求出了新的sa值。在求出sa后,下一步是计算rank值。
     44        for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
     45        x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
     46      }
     47 }
     48 
     49 int rank[maxn],height[maxn];
     50 
     51 //得到height数组:排名相邻的两个后缀的最长公共前缀
     52 void calheight(char *r,int *sa,int n)
     53 {
     54      cls(rank);
     55      cls(height);
     56      int i,j,k=0;
     57 
     58      for(i=1;i<n;i++) rank[sa[i]]=i;
     59     // for(i=0;i<n;i++)  printf("%d ",rank[i]); putchar(10); system("pause");
     60 
     61      for(i=0;i<n;height[rank[i++]]=k)
     62          for(k?k--:0,j=sa[((rank[i]-1<0)?0:rank[i]-1)];r[i+k]==r[j+k]&&i!=j;k++);
     63      return;
     64 }
     65 
     66 char ca[maxn];
     67 int sa[maxn];
     68 int N;
     69 int minh[maxn];
     70 
     71 int main()
     72 {
     73     int i;
     74     while (~scanf("%s",ca))
     75     {
     76         N = strlen(ca);
     77         if(ca[0]=='.')   break;
     78         ca[N] = '#';
     79         N++;
     80         da(ca, sa, N, 130);
     81         calheight(ca,sa,N);
     82 
     83      //  for(i=0;i<N;i++)  cout<<rank[i]<<" "; cout<<endl;
     84      //   for(i=0;i<N;i++)  cout<<height[i]<<" "; cout<<endl;
     85 
     86      //   for(i=0;i<N;i++)  cout<<sa[i]<<" "; cout<<endl;
     87         int i;
     88         
     89         int mins = height[rank[0]];
     90         for(i=rank[0];i>0;i--)
     91         {
     92             if(mins>height[i])
     93             {
     94                 mins = height[i];
     95             }
     96             minh[i-1] = mins;
     97         }
     98         mins = height[rank[0]];
     99         for(i=rank[0];i<N;i++)
    100         {
    101             if(mins>height[i])
    102             {
    103                 mins = height[i];
    104             }
    105             minh[i] = mins;
    106         }
    107     
    108          for (i=1;i<N;i++)
    109          {
    110             if ((N-1) % i==0&&minh[rank[i]]==N-1-i)
    111             {
    112                 printf("%d
    ",(N-1) / i);
    113                 break;
    114             }
    115          }
    116     }
    117     return 0;
    118 }
  • 相关阅读:
    SQL里面的函数应用
    Split的小用法
    堆栈和堆问题
    break,continue,goto,Return几个方法
    接口笔记
    抽象类
    虚方法
    将博客搬至CSDN
    运行数据区
    美团-走迷宫
  • 原文地址:https://www.cnblogs.com/crazyapple/p/3208841.html
Copyright © 2020-2023  润新知