HDU2865 Birthday Toy

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2865

题意:n个小圆组成的正n边形,中间有一个大圆。有木棍相连的两个圆不能有相同的颜色,旋转后相同视为相同的方案,求着色方案数。

HDU2865 Birthday Toy

思路:中间选一种颜色,剩下的是K-1种。设K=K-1。设f[n]表示n个小球的合法方案数。其中第一个和第n个的颜色不同。若第一个与第n-1个颜色相同,f[n]=f[n-2]*(K-1),否则f[n]=f[n-1]*(K-2),所以f[n]=f[n-2]*(K-1)+f[n-1]*(K-2)。因此,枚举n的约数t,则ans=sigama(f[t]*eular(n/t))。



int n,K;



class Matrix

{

public:

    i64 a[N][N];



    Matrix()

    {

        clr(a,0);

    }



    void init(int x)

    {

        if(x==0) a[0][0]=a[0][1]=a[1][0]=a[1][1]=0;

        else if(x==1) a[0][0]=a[1][1]=1,a[0][1]=a[1][0]=0;

        else

        {

            a[0][0]=K-2;

            a[0][1]=1;

            a[1][0]=K-1;

            a[1][1]=0;

        }

    }

};



Matrix operator*(Matrix &a,Matrix &b)

{

    int i,j,k;

    Matrix p;

    p.init(0);

    FOR0(i,2) FOR0(j,2) FOR0(k,2)

    {

        (p.a[i][j]+=a.a[i][k]*b.a[k][j]%mod)%=mod;

    }

    return p;

}



Matrix operator^(Matrix a,int t)

{

    Matrix ans;

    ans.init(1);

    while(t)

    {

        if(t&1) ans=ans*a;

        a=a*a;

        t>>=1;

    }

    return ans;

}



Matrix a;

int prime[M],tag[M],cnt;

vector<int> factor;





void init()

{

    int i,j;

    for(i=2;i<180;i++) if(!tag[i])

    {

        for(j=i*i;j<M;j+=i) tag[j]=1;

    }

    for(i=2;i<M;i++) if(!tag[i])

    {

        prime[++cnt]=i;

    }

}



void split()

{

    factor.clear();

    int i;

    for(i=1;i*i<n;i++) if(n%i==0)

    {

        factor.pb(i);

        factor.pb(n/i);

    }

    if(i*i==n) factor.pb(i);

}





int eular(int n)

{

    int ans=n,i;

    for(i=1;i<=cnt&&(i64)prime[i]*prime[i]<=n;i++) if(n%prime[i]==0)

    {

        ans=ans/prime[i]*(prime[i]-1);

        while(n%prime[i]==0) n/=prime[i];

    }

    if(n>1) ans=ans/n*(n-1);

    return ans;

}



i64 exGcd(i64 a,i64 b,i64 &x,i64 &y)

{

    if(!b)

    {

        x=1;y=0;

        return a;

    }

    i64 r=exGcd(b,a%b,x,y);

    i64 temp=x;

    x=y;

    y=temp-a/b*y;

    return r;

}



i64 reverse(int a)

{

    i64 x,y;

    exGcd(a,mod,x,y);

    x=(x%mod+mod)%mod;

    return x;

}





i64 get(int n)

{

    i64 ans=0;

    if(n==1) ans=0;

    else if(n==2) ans=(i64)K*(K-1)%mod;

    else if(n==3) ans=(i64)K*(K-1)%mod*(K-2)%mod;

    else

    {

        a.init(2);

        a=a^(n-3);

        ans+=a.a[0][0]*K%mod*(K-1)%mod*(K-2)%mod;

        ans+=a.a[1][0]*K%mod*(K-1)%mod;

    }

    return ans%mod;

}



int main()

{

    init();

    while(scanf("%d%d",&n,&K)!=-1)

    {

        K--;

        split();

        i64 ans=0;

        int i;

        FOR0(i,SZ(factor))

        {

            ans+=get(factor[i])*eular(n/factor[i])%mod;

            if(ans>=mod) ans-=mod;

        }

        ans=ans*reverse(n)%mod*(K+1)%mod;

        printf("%I64d\n",ans);

    }

    return 0;

}

  

你可能感兴趣的:(birt)