hdu4333Revolving Digits 扩展kmp

来源:互联网 发布:兰格钢铁 知乎 编辑:程序博客网 时间:2024/05/16 06:40
//给出一个长度为n的(n<<100000)字符串//将这个字符串通过旋转可以得到n个字符串//问这n个字符串有多少个不同的大于,等于,小于原来的字符串的个数//通过将这个字符串t复制一个再其后面得到一个新的字符串s=t+t//在用扩展kmp求出新的字符串后缀与原来字符串的最长公共前缀//对于ex[i]>=n肯定相等,否则只需要比较一下他们后面的一个数的大小//至于重复次数可以用kmp求出循环节的个数#include<cstdio>#include<cstring>#include<iostream>#include<string>using namespace std ;const int maxn = 2e5+10 ;string s ;string t ;int Next[maxn] ;int ex[maxn] ;int nn[maxn] ;void get_next(){    int n = t.length() ;    Next[0] = n ;    int j = 0 ;    while(t[j] == t[j+1] && j + 1 < n)    j++ ;    Next[1] = j ;    int a = 1 ;    int p = a + Next[a] - 1 ;    for(int i = 2;i < n;i++)    {        int l = Next[i-a] ;        if(l+i-1>=p)        {            int k = max(p-i+1 , 0) ;            while(t[i+k]==t[k] && i+k < n)            k++ ;            Next[i] = k ;            a = i ; p = Next[a] + a - 1 ;        }        else Next[i] = l ;    }}void get_ex(){    int n = s.length() ;    int m = t.length() ;    int j = 0 ;    while(s[j] == t[j] && j < min(n , m))    j++ ;    ex[0] = j ;    int a = 0 ;    int p = ex[a] + a - 1 ;    for(int i = 1;i < n;i++)    {        int l = Next[i-a] ;        if(l + i - 1 >= p)        {            int k = max(p - i + 1 , 0 ) ;            while(s[i+k] == t[k] && i + k < n && k < m)            k++ ;            ex[i] = k ;            a = i ;            p = ex[a] + a - 1 ;        }        else ex[i] = l ;    }}void get_nn(){    int j = 0 ;    int k = -1 ;    nn[0] = -1 ;    int n = t.length();    while(j < n)    {        if(k == -1 || t[j] == t[k])        {            j++;            k++ ;            nn[j] = k ;        }        else k = nn[k] ;    }}int main(){    std::ios_base::sync_with_stdio(false) ;    int T ;    int cas = 0 ;    cin>>T ;    while(T--)    {        cin>>t ;        int ans = 1 ;        int n = t.length() ;        get_nn() ;        if(n%(n-nn[n]) == 0)        ans = n/(n-nn[n]) ;        s = t + t ;        get_next() ;        get_ex() ;        int mi = 0 ;        int eq = 0 ;        int ma = 0 ;        for(int i = 0;i < n;i++)        if(ex[i] >= n)eq++ ;        else if(s[i+ex[i]] > t[ex[i]])ma++ ;        else mi++ ;        cout<<"Case "<<++cas<<": "<<mi/ans<<" "<<eq/ans<<" "<<ma/ans<<endl ;    }    return 0 ;}

0 0
原创粉丝点击