Power Strings POJ - 2406

看到POJ一个人的帖感觉很棒

Posted by georgezhang at 2010-01-07 05:36:08 on Problem 2406


设字符串s长度为l(l不超过1000000),如果s形如u^k,则称s具有周期数k

引理一
设s具有周期数m,n,令h为m,n的最小公倍数,那么s具有周期数h

引理二
对l进行素因子分解,那么不同的素数最多出现7个

引理三
设l[0],l[1],...,l[r]为一个有限长的正整数数列,满足l[k+1]整除l[k](0<=k<=r-1),
l[0]=l,并且满足l[k+1]=l[k]的k最多不超过7个,
那么l[0]+l[1]+...+l[r]<=7*l,等号成立当且仅当r=6,l[0]=l[1]=...=l[6]

算法

(1)对l进行素因子分解,得到 l=p[0]^t[0]*p[1]^t[1]*...*p[d]^t[d]
其中p[0]<p[1]<...<p[d]为素数,t[k]为正整数(0<=k<=d)

(2)设置初值k:=0,T:=1,执行下面循环,直到k=d+1结束
{
如果t[k]>0且s具有周期数p[k]
   记s:=s'^p[k]
   令s:=s',T:=T*p[k]
   t[k]:=t[k]-1
若条件不成立k:=k+1
}
T即为所求

算法的正确性由引理一保证,根据引理一,s的所有可能的周期数都是最大周期数的约数,又由于最大周期数是l的约数,算法正确性得证。

使用最朴素的方法检查“s是否具有周期数p[k]”,复杂度与length(s)成正比,
记为C*length(s),可以证明,该算法复杂度不超过7*C*l

如果每次执行判断“s是否具有周期数p[k]”时,记下当前的length(s),我们得到数列
l[0],l[1],...,l[r],
那么,算法的复杂度就是C*(l[0]+l[1]+...+l[r])。
借助引理二,可以证明,这个数列满足引理三的条件,因此得到最大复杂度7*C*l。
同时,我们还知道,最大复杂度在周期数是1的时候取得。
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <set>
#include <queue>
#include <cstring>
#include <string>
#include <limits.h>
#include <string.h>
#include <vector>
#include <map>
#define LL long long
#define INF 2100000000
#define fi first
#define se second
#define lowbit(x) (x&(-x))
#define eps 5e-7
using namespace std;
const int maxn=(int)1e6 +10;
const int maxm=(int)1e3+10;
const LL MOD=(LL)1e9+7;
char s[maxn];
int p[maxm];
int t[10];
void getprime(){
    for(int i=2;i<maxm;i++){
        if(!p[i])p[++p[0]]=i;
        for(int j=1;j<=p[0]&&p[j]*i<maxm&&i%p[j];j++)
            p[p[j]*i]=1;
    }
}
bool check(int L,int l){
   // printf("L:%d l:%d\n",L,l);
    if(l==1)return true;
    for(int i=L;i<l;i+=L){
        for(int k=0;k<L;k++){
            if(s[k]!=s[k+i])return false;
        }
    }return true;
}
int main()
{
#ifdef shuaishuai
    freopen("C:\\Users\\hasee\\Desktop\\a.txt","r",stdin);
    //freopen("C:\\Users\\hasee\\Desktop\\b.txt","w",stdout);
#endif
    getprime();
    while(~scanf("%s",s)){
        if(s[0]=='.'&&s[1]==0)break;
        int l=strlen(s);
        int tmp=l;
        memset(t,0,sizeof t);
        for(int i=1;i<=p[0];i++){
            while(tmp&&tmp%p[i]==0)tmp/=p[i],t[i]++;
        }
        int T=1;
        for(int i=1;i<=p[0]&&p[i]<=l;i++){
            //printf("l :%d p[i] :%d\n",l,p[i]);
            while(l&&t[i]>0&&check(l/p[i],l))
            {

                l/=p[i];t[i]--;
                T*=p[i];
            }
        }
        cout<<T<<endl;
    }
    return 0;
}

 

posted @ 2017-09-11 21:44  MeowMeowMeow  阅读(154)  评论(0编辑  收藏  举报