1. 程式人生 > >Power Strings P5019

Power Strings P5019

Description

給定若干長度小於等於1000000000的字串,詢問每個字串最多由多少個相同的子串重複連線而成(迴圈節),例如ababab,最多由3個ab連線而成


Input

若干行,每行一個字串。最後一行是一個"."點號,作為輸入的結尾


Output

對應輸入的每行,計算最多有多少個相同子串連線而成


Hint

This problem has huge input, use scanf instead of cin to avoid Time Limit Exceed.


Solution

列舉從1到m的子串長度並且用cnt來記錄出現的次數肯定要超時,因為是O(m^2)的時間複雜度,而m是百萬級別的資料。既然出現了迴圈節,那麼迴圈的次數,也就是出現的次數=m/迴圈節的長度,那麼迴圈節就一定是m的因數,用ins陣列來存放m的所有因數。然後setb和sethash,定義findhash為bool型別返回一個迴圈節是否跟S串匹配,如果匹配,那麼就輸出答案,如果沒有就繼續找。由於這個是單調的,子串長度越小那麼答案就越大,所以從小到大找只要findhash返回true就輸出m/ins[i]。


注意事項:
1、不用把陣列清零了會把power清掉。。。
2、if語句下面只管一句所以不要忘了{}。。。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 1000005
#define inf 0x3f3f3f3f
#define ull unsigned long long
using namespace std;
char S[maxn];
ull power[maxn],sumb,ha[maxn];
int ins[maxn];
int m,cnt;
void setins(){
    cnt=0; 
    m=strlen(S+1);
    for(int k=1;k<=sqrt(m);k++){
        if(k*(m/k)==m){
            ins[++cnt]=k;
            ins[++cnt]=m/k;
        }
    }
    sort(ins+1,ins+1+cnt);
}
void setb(int b){
    power[0]=1;
    for(int i=1;i<=m;i++){
        power[i]=power[i-1]*b;
    }
}
void sethash(int b){
    ha[0]=0;
    for(int i=1;i<=m;i++){
        ha[i]=ha[i-1]*b+S[i]-'A'+1;
    }
}
bool findhash(int i){
    int len=ins[i];
    for(int j=1;j+len-1<=m;j+=len){
        if(ha[len]!=ha[j+len-1]-ha[j-1]*power[len])return false;
    }
    return true;
}
int main(){
    while(1){
        scanf("%s",S+1);
        if(S[1]=='.')break;
        else{
            setins();
            setb(53);
            sethash(53);
            for(int i=1;i<=cnt;i++){
                if(!findhash(i))continue;
                else{
                    printf("%d\n",m/ins[i]);
                    break;
                }
            }
        }
    }
    return 0;
}