POJ burnside&&polya整理练习

POJ 2409 Let it Bead 

这题就是polya公式的直接套用,唯一麻烦的是置换群的种类数,由于可以翻转,所以除了要加上pow(c,gcd(s,i))这些平面旋转的置换群,还要加上翻转的。由于翻转的情况奇偶是不同的,所以需要分开讨论:偶数:pow(c,(s-2)/2+2)*(s/2)+pow(c,(s/2))*(s/2);(里面包含了两个对点和两个对边的旋转) 奇数:pow(c,(s-1)/2+1)*s;(一个点和对边的旋转)

 

#include<iostream>

#include<cstdio>

#include<algorithm>

#include<cstring>

#include<string>

#include<cmath>

#include<set>

#include<vector>

#define mem(a,b) memset(a,b,sizeof(a))

#define FOR(a,b,i) for(i=a;i<=b;++i)

#define For(a,b,i) for(i=a;i<b;++i)

using namespace std;

inline void RD(int &ret)

{

    char c;

    do

    {

        c=getchar();

    }

    while(c<'0'||c>'9');

    ret=c-'0';

    while((c=getchar())>='0'&&c<='9')

    {

        ret=ret*10+(c-'0');

    }

}

inline void OT(int a)

{

    if(a>=10)

    {

        OT(a/10);

    }

    putchar(a%10+'0');

}

int gcd(int a,int b)

{

    if(b==0)

    {

        return a;

    }

    else

    {

        return gcd(b,a%b);

    }

}

int pow(int x,int y)

{

    int i,j=1;

    for(i=0;i<y;++i)

    {

        j*=x;

    }

    return j;

}

int main()

{

    int c,s,i,j,ans,sum;

    while(1)

    {

        RD(c);

        RD(s);

        if(c==0&&s==0)

        {

            break;

        }

        sum=0;

        for(i=1;i<=s;++i)

        {

            sum+=pow(c,gcd(i,s));//通用做法,而且数据量很小。

        }

        if(s%2==0)//注意题意,这题的图案是可以翻转的,但并不是所有题目都这样,注意观察

        {

            sum+=pow(c,(s-2)/2+2)*(s/2)+pow(c,(s/2))*(s/2);

        }

        else

        {

            sum+=pow(c,(s-1)/2+1)*s;

        }

        ans=sum/(2*s);

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

    }

    return 0;

}

POJ 1286 Necklace of Beads

 

典型的买一送一题,和上题一样,都是套用公式题目,这题和上题相比,还少了可以翻转的条件,而且颜色数量固定为3,所以就不过多赘述了。但要注意N=0时要特判一下,输出0。而且数据范围比之前那题大,要使用long long。

 

#include<iostream>

#include<cstdio>

#include<algorithm>

#include<cstring>

#include<string>

#include<cmath>

#include<set>

#include<vector>

#define mem(a,b) memset(a,b,sizeof(a))

#define FOR(a,b,i) for(i=a;i<=b;++i)

#define For(a,b,i) for(i=a;i<b;++i)

using namespace std;

inline void RD(int &ret)

{

    char c;

    do

    {

        c=getchar();

    }

    while(c<'0'||c>'9');

    ret=c-'0';

    while((c=getchar())>='0'&&c<='9')

    {

        ret=ret*10+(c-'0');

    }

}

inline void OT(int a)

{

    if(a>=10)

    {

        OT(a/10);

    }

    putchar(a%10+'0');

}

int gcd(int a,int b)

{

    if(b==0)

    {

        return a;

    }

    else

    {

        return gcd(b,a%b);

    }

}

long long pow(int x,int y)//注意数据范围,3的18次方就超了

{

    int i;

    long long j=1;

    for(i=0; i<y; ++i)

    {

        j*=x;

    }

    return j;

}

int main()

{

    int s,i;

    long long ans,sum;

    while(1)

    {

        scanf("%d",&s);

        if(s==-1)

        {

            break;

        }

        if(s==0)

        {

            printf("0\n");

        }

        else

        {

            sum=0;

            for(i=1; i<=s; ++i)

            {

                sum+=pow(3,gcd(i,s));

            }

            if(s%2==0)

            {

                sum+=pow(3,(s-2)/2+2)*(s/2)+pow(3,(s/2))*(s/2);

            }

            else

            {

                sum+=pow(3,(s-1)/2+1)*s;

            }

            ans=sum/(2*s);

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

        }

    }

    return 0;

}

 

 

POJ 2154 Color

这题就不是简单的套用公式就可以过了,由于数据量很大,所以我们就需要使用筛素数结合欧拉函数求解的方式优化复杂度。而且数据范围的原因,很多人为了图省事,确保不会吵范围就用long long定义了事,却发现TLE,所以在写这题是必须还是要使用int定义,而且需要在很多地方取模。注意:快速幂部分取模一定要频繁,每个数在进行运算之前都需要取模。

 

#include<iostream>

#include<cstdio>

#include<algorithm>

#include<cstring>

#include<string>

#include<cmath>

#include<set>

#include<vector>

#define mem(a,b) memset(a,b,sizeof(a))

#define FOR(a,b,i) for(i=a;i<=b;++i)

#define For(a,b,i) for(i=a;i<b;++i)

using namespace std;

inline void RD(int &ret)

{

    char c;

    do

    {

        c=getchar();

    }

    while(c<'0'||c>'9');

    ret=c-'0';

    while((c=getchar())>='0'&&c<='9')

    {

        ret=ret*10+(c-'0');

    }

}

inline void OT(int a)

{

    if(a>=10)

    {

        OT(a/10);

    }

    putchar(a%10+'0');

}

int N;

int p(int x,int y)//取模一定要反复,我就是因为这个WA的

{

    int res=1;

    while(y>0)

    {

        if(y%2==1)

        {

            res=(res%N)*(x%N)%N;

        }

        x=(x%N)*(x%N)%N;

        y/=2;

    }

    return res%N;

}

int e(int n)

{

    int ans=1,i;

    for(i=2; i*i<=n; i++)

    {

        if(n%i==0)

        {

            ans*=i-1;

            n/=i;

            while(n%i==0)

            {

                ans*=i;

                n/=i;

            }

        }

    }

    if(n>1)

    {

        ans*=n-1;

    }

    return ans;

}

int main()

{

    int i,t,s;

    __int64 sum;

    RD(t);

    while(t--)

    {

        scanf("%d%d",&s,&N);

        sum=0;

        for(i=1; i*i<=s; ++i)

        {

            if(s%i==0)

            {

                sum=(sum+e(s/i)%N*p(s,i-1))%N;//这是求polya计数的通用优化方式

                if(i*i!=s)

                {

                    sum=(sum+e(i)%N*p(s,s/i-1))%N;//也要注意取模方式

                }

            }

        }

        printf("%I64d\n",sum%N);

    }

    return 0;

}


POJ 2888 Magic Bracelet

 

超好的组合题,这题是burnside的范围,因为burnside求有限制条件的组合数是很有效果的。这题用到了很多知识burnside+矩阵乘+矩阵快速幂+快速幂取模+欧拉函数+筛素数法+离散数学的知识。运用离散数学的知识将珠子的组合关系建图,转化为矩阵就是1为a和b可联通,0为a和b不可相联。而此矩阵的k次方就代表了经过k条路到达的方案数。

然后再结合欧拉函数优化就可以得到答案了。

 

#include<iostream>

#include<cstdio>

#include<algorithm>

#include<cstring>

#include<string>

#include<cmath>

#include<set>

#include<vector>

#define mem(a,b) memset(a,b,sizeof(a))

#define FOR(a,b,i) for(i=a;i<=b;++i)

#define For(a,b,i) for(i=a;i<b;++i)

#define N 9973

using namespace std;

inline void RD(int &ret)

{

    char c;

    do

    {

        c=getchar();

    }

    while(c<'0'||c>'9');

    ret=c-'0';

    while((c=getchar())>='0'&&c<='9')

    {

        ret=ret*10+(c-'0');

    }

}

inline void OT(int a)

{

    if(a>=10)

    {

        OT(a/10);

    }

    putchar(a%10+'0');

}

int s,m,k,tx[11][11],ty[11][11],tz[11][11];

int p(int x,int y)//快速幂取模

{

    int res=1;

    x=x%N;

    while(y>0)

    {

        if(y%2==1)

        {

            res=(res*x)%N;

        }

        x=(x*x)%N;

        y/=2;

    }

    return res%N;

}

int e(int n)//欧拉函数优化

{

    int ans=1,i;

    for(i=2; i*i<=n; i++)

    {

        if(n%i==0)

        {

            ans*=i-1;

            n/=i;

            while(n%i==0)

            {

                ans*=i;

                n/=i;

            }

        }

    }

    if(n>1)

    {

        ans*=n-1;

    }

    return ans%N;//注意取模,不然会超

}

void mat(int a[11][11],int b[11][11])//矩阵乘

{

    int d[11][11],i,j,l;

    mem(d,0);

    For(0,m,i)

    {

        For(0,m,j)

        {

            For(0,m,l)

            {

                d[i][j]=(d[i][j]+a[i][l]*b[l][j])%N;

            }

        }

    }

    For(0,m,i)

    {

        For(0,m,j)

        {

            a[i][j]=d[i][j];

        }

    }

}

int g(int x)

{

    mem(ty,0);

    int i,j,ans;

    For(0,m,i)

    {

        For(0,m,j)

        {

            tz[i][j]=tx[i][j];

        }

    }

    For(0,m,i)

    {

        ty[i][i]=1;

    }

    while(x>0)//矩阵快速幂

    {

        if(x%2==1)

        {

            mat(ty,tz);

        }

        mat(tz,tz);

        x/=2;

    }

    ans=0;

    For(0,m,i)

    {

        ans=(ans+ty[i][i])%N;

    }

    return ans;

}

int main()

{

    int i,j,t,a,b;

    int sum;

    RD(t);

    while(t--)

    {

        RD(s);

        RD(m);

        RD(k);

        For(0,m,i)

        {

            For(0,m,j)

            {

                tx[i][j]=1;

            }

        }

        For(0,k,i)

        {

            RD(a);

            RD(b);

            a--;

            b--;

            tx[a][b]=tx[b][a]=0;//建图

        }

        sum=0;

        for(i=1; i*i<=s; ++i)

        {

            if(s%i==0)//其他过程与上题类似

            {

                sum=(sum+(e(s/i)*g(i))%N)%N;

                if(i*i!=s)

                {

                    sum=(sum+(e(i)%N*g(s/i))%N)%N;

                }

            }

        }

        printf("%d\n",(sum*(p(s,N-2)%N))%N);

    }

    return 0;

}


burnside&&polya还有很多神奇的应用,希望可以与大家多多交流经验~

 


 

你可能感兴趣的:(ide)