zoukankan      html  css  js  c++  java
  • 【扩展kmp+最小循环节】HDU 4333 Revolving Digits

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

    【题意】

    • 给定一个数字<=10^100000,每次将该数的第一位放到放到最后一位,求所有组成的不同的数比原数小的个数,相等的个数,大的个数

    【思路】

    • 这个数很大,用字符串处理
    • 比较两个字符串的大小,一位一位很耗时,可以求出最长公共前缀,只比较最长公共前缀后一位
    • 每次将数的最后一位放到最后一位,如abcd变成dabc,cdab,bcda,相当于abcdabcd各个后缀的前四位
    • 这样就变成了求abcdabcd的每个后缀与abcd的最长公共前缀,用扩展KMP线性求
    • abab这种情况按上面的做法abababab会考察ab,ba,ab,ba,有重复的,是因为abab=(ab)^2,所以还要考虑最小循环节去重

    【AC】

      1 #include<iostream>
      2 #include<cstring>
      3 #include<string>
      4 #include<cstdio>
      5 #include<algorithm>
      6 using namespace std;
      7 typedef long long ll;
      8 const int maxn=2e5+3;
      9 char s[maxn];
     10 char t[maxn];
     11 int nxt[maxn];
     12 int extend[maxn];
     13 int nxtval[maxn];
     14 
     15 
     16 void pre_EKMP(char x[],int m,int nxt[])
     17 {
     18     nxt[0]=m;
     19     int j=0;
     20     while(j+1<m && x[j]==x[j+1]) j++;
     21     nxt[1]=j;
     22     int k=1;
     23     for(int i=2;i<m;i++)
     24     {
     25         int p=nxt[k]+k-1;
     26         int L=nxt[i-k];
     27         if(i+L<p+1) nxt[i]=L;
     28         else
     29         {
     30             j=max(0,p-i+1);
     31             while(i+j<m && x[i+j]==x[j]) j++;
     32             nxt[i]=j;
     33             k=i;
     34         }
     35     }
     36 }
     37 
     38 void EKMP(char x[],int m,char y[],int n,int nxt[],int extend[])
     39 {
     40     pre_EKMP(x,m,nxt);//子串 
     41     int j=0;
     42     while(j<n && j<m &&x[j]==y[j]) j++;
     43     extend[0]=j;
     44     int k=0;
     45     for(int i=1;i<n;i++)
     46     {
     47         int p=extend[k]+k-1;
     48         int L=nxt[i-k];
     49         if(i+L<p+1) extend[i]=L;
     50         else
     51         {
     52             j=max(0,p-i+1);
     53             while(i+j<n && j<m && y[i+j]==x[j]) j++;
     54             extend[i]=j;
     55             k=i;
     56         }
     57     }
     58 }
     59 
     60 void kmp_pre(char x[],int m,int nxtval[])
     61 {
     62     int i,j;
     63     j=nxtval[0]=-1;
     64     i=0;
     65     while(i<m)
     66     {
     67         if(j==-1||x[i]==x[j])
     68         {
     69             i++;
     70             j++;
     71             if(x[i]!=x[j]) nxtval[i]=j;
     72             else  nxtval[i]=nxtval[j];
     73         }
     74         else j=nxtval[j];
     75     }
     76 
     77 }
     78 
     79 void NextVal(char *T)
     80 {
     81     int i=0,j=-1;
     82     nxtval[0]=-1;
     83     int Tlen=strlen(T);
     84     while(i<Tlen)
     85     {
     86         if(j==-1||T[i]==T[j])
     87         {
     88             i++;
     89             j++;
     90             if(T[i]!=T[j]) nxtval[i]=j;
     91             else  nxtval[i]=nxtval[j];
     92         }
     93         else j=nxtval[j];
     94     }
     95 }
     96 
     97 
     98 int main()
     99 {
    100     int T;
    101     scanf("%d",&T);
    102     int cas=0;
    103     while(T--)
    104     {
    105         scanf("%s",s);
    106         strcpy(t,s);
    107         strcat(s,t);
    108         int a,b,c;
    109         a=b=c=0;
    110         int ls=strlen(s);
    111         int lt=strlen(t);
    112         EKMP(t,lt,s,ls,nxt,extend);
    113         kmp_pre(t,lt,nxtval);
    114         int p=lt-nxtval[lt];
    115         int tmp=1;
    116         if(lt%p==0) tmp=lt/p;
    117         for(int i=0;i<lt;i++)
    118         {
    119             if(extend[i]==lt) a++;
    120             else if(s[i+extend[i]]>t[extend[i]]) c++;
    121             else b++;
    122         }
    123         printf("Case %d: %d %d %d
    ",++cas,b/tmp,a/tmp,c/tmp);
    124     }
    125     return 0;
    126 }
    扩展kmp求最小循环节方法一:kmp预处理
    扩展kmp计算最小循环节方法二:利用已知的next数组

    【知识点】

    扩展kmp的next数组与kmp数组的next含义不同,是字符串s的所有后缀和s本身的最长公共前缀

    【坑点】

    做这道题踩了各种坑

    • strcat函数的用法:strcat(s,s)是错误的,会T,strcat的两个参数传的是指针,就是s在内存里面的位置,这里两个s是同一个东西 第一个s变长的时候,第二个s也会变长,然后就没完没了了
    •  
  • 相关阅读:
    负外边距--转载
    研究Dropbox Server端文件系统
    Bluetooth Profile for iPhone from the functional perspectives
    Somebody That I Used to Know
    复合查询
    聚合查询
    Filter查询
    ES基本查询
    ES版本控制
    ES基本操作
  • 原文地址:https://www.cnblogs.com/itcsl/p/7399750.html
Copyright © 2011-2022 走看看