hdu 4187 Alphabet Soup polya原來還可以這樣

哎,想寫一個解題報告的,但是,寫出來看着就不舒服,最後還是刪了。囧

這個題,明顯的是polya問題,最核心的東西是:當這個旋轉a個角度之後和原先的重合,那麼旋轉2*a個角度之後仍然重合,當然,旋轉一週(36000)之後仍然重合。是的,我們可以看到,這個最小的a“區間”就是“項鍊”問題的一個珠子,然後就是若干個珠子的polya,直接模板!!求這個a的時候用到的東西是 :角度之間的距離然後kmp,

ok,不想多寫了,放上代碼吧,雖然貼代碼不是什麼好習慣,我就是給自己看的,上面的東西算是提示,goodluck!

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

const int N = 360010,P = 100000007,S = 360000;

int s,n;
int data[N],dis[N];
int next[N];
void get_next(){
    int i,j=-1;
    next[0]=-1;
    for(i=1;i<=n;i++){     //dis[j]是不是可以理解爲i的前一個字符的next值所指想的字符
        while(j>-1&&dis[j+1]!=dis[i])j=next[j];
        if(dis[j+1]==dis[i])j++;
        next[i]=j;
    }
}

//得到最小,使用dis數組,長度是n,從0開始,ok kmp實現
int getMin()
{
    int re = n;
    get_next();
    int l=(n-1)-next[n-1];
    if(n%l==0)re = l;
    return re;
}

long long pow(int a,int n)
{
    long long ret=1;
    long long A=a;
    while(n)
    {
        if (n & 1)
        {
            ret = (ret*A%P);
        }
        A = (A*A%P);
        n>>=1;
    }
    return ret;
}

long long GCD(long long a,long long b) {while(b){ long long t=a%b;a=b;b=t;}return a;}

long long inv( long long n )
{
    return pow( n, P - 2 )%P;
}
long long polya(long long c,int n)
{
    long long ans = 0;
    for(int i = 1;i <= n;i++)
        ans = (ans+pow(c,GCD(n,i)))%P;

    return (ans*inv(n)%P);
}

int main()
{
    while(scanf("%d%d",&s,&n) != EOF)
    {
        if(s == -1 && n == -1) break;
        for(int i = 0;i < n;i++)
            scanf("%d",&data[i]);

        sort(data,data+n);
        for(int i = 0;i < n;i++)
            dis[i] = (data[(i+1)%n]-data[i]+S)%S;

        int t = getMin();
        cout << polya(pow(s,t),n/t) << "\n";
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章