1. 程式人生 > >POJ 2406 Power Strings 解題報告(雜湊)

POJ 2406 Power Strings 解題報告(雜湊)

Power Strings
Time Limit: 3000MS Memory Limit: 65536K
Total Submissions: 32810 Accepted: 13670

Description

Given two strings a and b we define a*b to be their concatenation. For example, if a = "abc" and b = "def" then a*b = "abcdef". If we think of concatenation as multiplication, exponentiation by a non-negative integer is defined in the normal way: a^0 = "" (the empty string) and a^(n+1) = a*(a^n).

Input

Each test case is a line of input representing s, a string of printable characters. The length of s will be at least 1 and will not exceed 1 million characters. A line containing a period follows the last test case.

Output

For each s you should print the largest n such that s = a^n for some string a.

Sample Input

abcd
aaaa
ababab
.

Sample Output

1
4
3

Hint

This problem has huge input, use scanf instead of cin to avoid time limit exceed.

Source

    解題報告:正常做法是用KMP,求失敗指標什麼的。我這裡直接用字串雜湊和矩陣快速冪搞定了。

    首先從小到大列舉可能的重複串的長度,使用矩陣快速冪遞推最後一位的雜湊值,與實際計算的雜湊值比較,相同則說明當前子串為最小的重複串,此時n最大。

    程式碼如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <iomanip>
#include <cassert>
using namespace std;
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#define ff(i, n) for(int i=0;i<(n);i++)
#define fff(i, n, m) for(int i=(n);i<=(m);i++)
#define dff(i, n, m) for(int i=(n);i>=(m);i--)
#define bit(n) (1LL<<(n))
typedef long long LL;
typedef unsigned long long ULL;
void work();
int main()
{
#ifdef ACM
    freopen("in.txt", "r", stdin);
#endif // ACM

    work();
}

void nextInt(int & x)
{
    char ch;
    while(ch = getchar(), isdigit(ch) == false);

    x = 0;
    while(x = 10 * x + ch - '0', ch = getchar(), isdigit(ch) == true);
}

/*****************************************華麗分割線**********************************************/

ULL powULL(ULL a, int b)
{
    ULL ret = 1;
    while(b)
    {
        if(b&1)
            ret *= a;
        a *= a;
        b /= 2;
    }
    return ret;
}

struct Matrix
{
    ULL a[2][2];

    Matrix()
    {
        memset(a, 0, sizeof(a));
    }

    ULL* operator[](int i)
    {
        return a[i];
    }

    Matrix operator*(const Matrix & b) const
    {
        Matrix c;
        ff(i, 2) ff(j, 2) ff(k, 2)
            c[i][j] += a[i][k] * b.a[k][j];
        return c;
    }
};

Matrix powMatrix(Matrix a, int b)
{
    Matrix ret;
    ret[0][0] = ret[1][1] = 1;

    while(b)
    {
        if(b&1)
            ret = ret * a;
        a = a * a;
        b /= 2;
    }
    return ret;
}

template<int Size>
struct HashString
{
    ULL h[Size];

    void init(char * s, int len = -1)
    {
        if(len == -1) len = strlen(s);

        fff(i, 1, len)
            h[i] = h[i-1] * 29 + *s++;
    }

    ULL get(int sta, int len)
    {
        return h[sta + len] - h[sta] * powULL(29, len);
    }
};

HashString<10000003> hs;

char str[1111111];

void work()
{
    while(scanf("%s", str) == 1)
    {
        int len = strlen(str);
        if(len == 1 && str[0] == '.') break;

        hs.init(str, len);

        fff(i, 1, len) if(len % i == 0)
        {
            Matrix a;
            a[0][0] = a[0][1] = hs.get(0, i);

            Matrix b;
            b[1][0] = b[1][1] = 1;
            b[0][0] = powULL(29, i);
            b = powMatrix(b, len/i - 1);

            a = a * b;
            if(a[0][0] == hs.h[len])
            {
                printf("%d\n", len/i);
                break;
            }
        }
    }
}