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;
}


你可能感兴趣的:(hdu 4187 Alphabet Soup polya原来还可以这样)