zoukankan      html  css  js  c++  java
  • 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
    ",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
    ");
            }
            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
    ",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
    ",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
    ",(sum*(p(s,N-2)%N))%N);
        }
        return 0;
    }


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


  • 相关阅读:
    对返回的json数据重写格式,用特性JsonConverter
    dev 的NavBarControl动态菜单
    获取oracel数据库的结构
    Java-背单词程序(俄语)
    实现同或操作 C++
    输入字符串先用cin后用getline函数失效原因
    C++全局变量与局部变量
    4.Redis事务
    3.持久化配置
    2.常用数据类型
  • 原文地址:https://www.cnblogs.com/pangblog/p/3263223.html
Copyright © 2011-2022 走看看