【POJ

来源:互联网 发布:win10网络图标红叉 编辑:程序博客网 时间:2024/06/16 11:20

这两个题目就是一个题目。
题意: 有一个长度为n的项链,现在给m个颜色的珠子,每种的珠子个数都是无限个,现在问你能够做成几个本质不同的项链(如果两个项链不能够通过旋转或者翻转达到相同,则认为本质不同) 。

在做这个题目之前最好把群相关的知识点看看。
分析 :
现在给了两种操作可能使项链相同 , 翻转和旋转。 我们一个个来分析。

1 》 旋转
首先旋转的话,可能会旋转一个珠子,旋转两个珠子,等等,这样的话,就会产生G=n种置换。 且每种置换的循环节数为gcd(i,n) i表示旋转i个珠子。
为什么每种置换的循环节数为gcd(i,n)呢? 证明如下:
我们假设当前所在的珠子为p,旋转了x个珠子。则对于当前置换的一个循环就可以表示为 p+k*x = p (mod n) (此时的k就是当前循环中元素的个数) 化简一下 k * x = 0 ( mod n ) 则可知 k * x 为n的倍数,现在我们肯定是要求最小的k, 所以 k * x = lcm( n, x ) ,转化为一下 k * x = x * n / (gcd ( n , x )) , k = n / gcd ( n , x ) 由于对称性当前置换下每个循环中元素个数肯定是相等的且都是k,所以 当前置换下就有 gcd(n,x)个循环数。

2 》 翻转
(1) 当n 为奇数时
我们可以以将任意一个珠子作为对称轴来进行翻转,所以就有G= n种置换,且每个置换中循环的个数为(n-1)/2+1 .
证明如下 :
假使 我们以其中任意一个珠子来作为对称轴进行翻转,则就会将(n-1)个珠子分为左右两侧,左侧第一个珠子和右侧第一个珠子肯定可以相互转换 这是第一个循环,左侧第二个珠子和右侧第二个珠子肯定可以相互转化, 这使第二个循环,同理下去,共有(n-1)/2个循环,但是不要忘记了,你作为对称轴的珠子,自己本身为不动元,肯定可以作为一个循环。 故结果为 (n-1) / 2 +1 .

(2) 当n为偶数时候
为了好说明,我假设n个珠子形成的环,将其作为正n边形来看待。 ( 这样不会改变其性质)
< 1 > 我们以相对的两个边的连线为对称轴做翻转,所以这样就产生了G = n / 2个置换。 对于每个置换中循环的个数为 n / 2
证明如下:
我们现在任意以两个相对的边的连线作为对称轴,就会将所有的n个珠子分为两侧, 左侧第一个珠子和右侧第一个珠子肯定可以相互转换 这是第一个循环,左侧第二个珠子和右侧第二个珠子肯定可以相互转化, 这使第二个循环,同理下去,共有 n / 2 个循环
< 2 > 我们以相对的两个点的连线为对称轴,这样就会产生G = n / 2 个置换。对于每个置换中循环的个数为 (n- 2 ) /2 +2 。
证明如下 :
我们现在任意以两个相对的点的连线作为对称轴,就会将(n-2)珠子分为两侧, 左侧第一个珠子和右侧第一个珠子肯定可以相互转换 这是第一个循环,左侧第二个珠子和右侧第二个珠子肯定可以相互转化, 这使第二个循环,同理下去 就会有 (n - 2 ) /2 个循环,别忘了,还有两个不动元呢,所以我们要加上2 ,故 (n - 2 ) / 2 +2 ….

好了 ,分析完上述的所有情况我们就可以用polya定理来求解了 :

这里写图片描述
之后就是分情况写代码了 ,代码中我写的也很清晰 。

#include<algorithm>#include<iostream>#include<math.h>using namespace std;typedef pair<int,int>pii;#define first fi#define second se#define  LL long long#define fread() freopen("in.txt","r",stdin)#define fwrite() freopen("out.txt","w",stdout)#define CLOSE() ios_base::sync_with_stdio(false)const int MAXN = 1e5;const int MAXM = 1e6;const int mod = 1e9+7;const int inf = 0x3f3f3f3f;LL gcd(LL a,LL b) { return b==0?a:gcd(b,a%b); }LL power(LL a,LL b){    LL base=a,s=1;    while(b){        if(b&1) s=s*base;        base=base*base;        b>>=1;    }    return s;}int main(){    CLOSE();//  fread();//  fwrite();    LL n,m;    while(cin>>m&&cin>>n&&(n||m)){ // m个颜色,n个对象        if(n==0) {            cout<<0<<endl;            continue;        }         LL G1=n; LL cnt1=0;  // 旋转         cnt1+=power(m,n);// i=0 时         for(int i=1;i<n;i++){            cnt1+=power(m,gcd(n,i));        }        LL G2=0,cnt2=0;  //  翻转         if(n&1) {// 奇数             G2+=n;             cnt2=cnt2+n*power(m,(n-1)/2+1);         } else { //偶数             G2+=n/2;  //对相对的两个边为对称轴             cnt2=cnt2+n/2*power(m,n/2);            G2+=n/2; // 以相对的两个点为对称轴             cnt2=cnt2+n/2*power(m,n/2+1);        }        LL ans=(cnt1+cnt2)/(G1+G2);        cout<<ans<<endl;    }    return 0;}