zoukankan      html  css  js  c++  java
  • HDU 4333 Revolving Digits [扩展KMP]

      其实是很裸的一道题,可能是因为几乎没用过扩展KMP,只想到用后缀数组,但这题的常数卡的很厉害,不用扩展KMP应该是过不了的。

      扩展KMP能求出一个串所有后缀串(即s[i...len])和模式串的最长公共前缀。于是只要将这个串复制一遍,求出该串每个后缀与其本身的最长公共前缀即可,当公共前缀>=len时,显然相等,否则只要比较下一位就能确定这个串与原串的大小关系。

      至于重复串的问题,只有当这个串有循环节的时候才会产生重复串,用KMP的next数组求出最小循环节,用长度除以最小循环节得到循环节个数,在将3个答案都除以循环节个数即可。

      

     1 #include <string.h>
     2 #include <stdio.h>
     3 #define MAXN 2000005
     4 int cas;
     5 char s[MAXN],s2[MAXN];
     6 int next[MAXN],ext[MAXN];
     7 int max(int x,int y){return x>y?x:y;}
     8 int len;
     9 int ExKMP(char *t,char *s){
    10     int lent=len,lens=len*2,ans=0;
    11     next[1]=lent;
    12     int j=1,k=2;
    13     while(j<lent&&t[j]==t[j+1])++j;
    14     next[2]=j-1;
    15     for(int i=3;i<=lent;i++){
    16         if(next[i-k+1]<k+next[k]-i)next[i]=next[i-k+1];
    17         else{
    18             j=max(k+next[k]-i,0);
    19             while(i+j<=lent&&t[i+j]==t[j+1])++j;
    20             next[i]=j,k=i;
    21         }
    22     }
    23     j=1,k=1;
    24     while(j<=lent&&j<=lens&&s[j]==t[j])++j;
    25     ext[1]=j-1;
    26     if(ext[1]==lent)ans++;
    27     for(int i=2;i<=lens;i++){
    28         if(next[i-k+1]<k+ext[k]-i)ext[i]=next[i-k+1];
    29         else{
    30             j=max(k+ext[k]-i,0);
    31             while(i+j<=lens&&j<lent&&s[i+j]==t[j+1])++j;
    32             ext[i]=j,k=i;
    33         }
    34         if(ext[i]==lent)ans++;
    35     }
    36     return ans;
    37 }
    38 int main(){
    39     //freopen("test.in","r",stdin);
    40     scanf("%d",&cas);
    41     for(int ca=1;ca<=cas;ca++){
    42         scanf("%s",s+1);
    43         len=strlen(s+1);
    44         for(int i=1;i<=len;i++)s2[i]=s2[i+len]=s[i];
    45         s2[len*2+1]='\0';
    46         ExKMP(s,s2);
    47         int x1=0,x3=0;
    48         for(int i=1;i<=len;i++){
    49             if(ext[i]<len){
    50                 if(s2[i+ext[i]]<s[ext[i]+1])x1++;
    51                 else x3++;
    52             }
    53         }
    54         next[1]=0;
    55         for(int i=2,j=0;i<=len;i++){
    56             while(j>0&&s[i]!=s[j+1])j=next[j];
    57             if(s[i]==s[j+1])++j;
    58             next[i]=j;
    59         }
    60         int tot=1;
    61         if(len%(len-next[len])==0)tot=len/(len-next[len]);
    62         printf("Case %d: %d %d %d\n",ca,x1/tot,1,x3/tot);
    63     }
    64     return 0;
    65 }

      

  • 相关阅读:
    【学习小记】一般图最大匹配——带花树算法
    如何检查oracle的归档空间是否满了
    Linux 的计划任务
    转 oracle的热备份和冷备份
    SQLException: Io 异常: Connection refused ERR=12514 ERR=1153异常处理过程
    查看oracle数据库版本
    ORACLE默认实例设置--linux
    oracle查看用户属于哪个表空间
    oracle默认数据库实例
    oracle 查看用户所在的表空间
  • 原文地址:https://www.cnblogs.com/swm8023/p/2661264.html
Copyright © 2011-2022 走看看