Pólya定理:用于解決等價類計數問題的,所謂等價類計數問題是指題目中會定義一種等價系,滿足這個關系的元素都會被看成同一類,并只需要統計一次,最終需要統計所有的不同方案數。
我們可以分三步來解決這個問題。
1.確定置換群G。
2.計算每個置換的循環節個數。
3.代入公式:(其中,m為顏色的種數)
。
( 一)基于正方形的置換:
設邊長為n的正方形,c種顏色。
旋轉只有 0,90,180,270度三種旋法。
旋0度,則置換的輪換數為nn
旋90度,n為偶數時,則置換的輪換數為nn/4,n為奇數,則置換的輪換數為(nn-1)/4+1
旋180度,n為偶數時,則置換的輪換數為nn/2,n為奇數,則置換的輪換數為(nn-1)/2+1
旋270度,n為偶數時,則置換的輪換數為nn/4,n為奇數,則置換的輪換數為(n*n-1)/4+1
反射 沿對角反射兩種,沿對邊中點連線反射兩種
n為偶數時,沿對邊中點連線反射兩種的置換輪換數為 nn/2
沿對角反射兩種的置換輪換數為 (nn-n)/2+n
n為奇數時,沿對邊中點連線反射兩種的置換輪換數為 (nn-n)/2+n
沿對角反射兩種的置換輪換數為 (nn-n)/2+n
https://vjudge.net/problem/HDU-1812
(高精度用java方便)
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
int n,s1,s2,s3,s4;
Scanner in=new Scanner(System.in);
BigInteger c,two=new BigInteger("2"),four=new BigInteger("4"),eight=new BigInteger("8");
while(in.hasNext())
{
n=in.nextInt();
c=in.nextBigInteger();
s3=n*n;
if((n&1)!=0){
s1=(n*n-1)/4+1;
s2=(n*n-1)/2+1;
}
else {
s1=n*n/4;
s2=n*n/2;
}
s4=(s3-n)/2+n;
BigInteger sum=BigInteger.ZERO;
sum=sum.add(c.pow(s1).multiply(two));
sum=sum.add(c.pow(s3));
sum=sum.add(c.pow(s2));
if((n&1)!=0)
{
sum=sum.add(c.pow(s4).multiply(four));
}
else
{
sum=sum.add(c.pow(s3/2).multiply(two));
sum=sum.add(c.pow(s4).multiply(two));
}
sum=sum.divide(eight);
System.out.println(sum.toString());
}
}
}
(二 )基于環形的置換:
一個由n個點組成的環
旋轉有n中置換:
對于每種置換輪換數為:gcd(n,i)
翻轉(對稱):
奇數時只有n種相同的置換:
一個頂點和一條邊的中點連線為軸(n個):pow(c,n/2+1)
偶數時分成兩大類置換:
1、邊和邊的中點連線為軸(n/2個):pow(c,n/2+1)
2、點和點的連線為軸(n/2個):pow(c,n/2)
參考博客
https://vjudge.net/problem/HDU-3923
#include<cstdio>
using namespace std;
const long long mod=1000000007;
typedef long long LL;
LL gcd(LL a,LL b)
{
return b==0?a:gcd(b,a%b);
}
LL pow_mod(LL a,LL b)
{
LL base=a,ans=1;
while(b)
{
if(b&1) ans=(ans*base)%mod;
b>>=1;
base=(base*base)%mod;
}
return ans;
}
LL rev(LL a)
{
return pow_mod(a,mod-2);
}
int main()
{
int t,cas=1;
scanf("%d",&t);
while(t--)
{
LL m,n;
scanf("%lld%lld",&m,&n);
LL ans=0;
for(int i=1;i<=n;i++)
{
ans=(ans+pow_mod(m,gcd(n,i)));
}
if(n&1)
{
ans=(ans+n*pow_mod(m,n/2+1))%mod;
}
else {
ans=(ans+n/2*pow_mod(m,n/2))%mod;
ans=(ans+n/2*pow_mod(m,n/2+1))%mod;
}
LL rever=rev(n*2);
printf("Case #%d: %lld\n",cas++,(ans*rever)%mod);
}
return 0;
}