这次真真是polya的题目了。。。。
但是好像是要用JAVA大数?不会的说,,,先把大数放着吧……这里有个JAVA速成,先MARK。
http://hi.baidu.com/czyuan_acm/item/2c115f6b3d35192469105bae
说说自己的想法吧。这算是个裸polya应用了。这两天一直在看书,组合数学这本书讲得很好,无奈脑子有点笨,也啃了挺久的。但是前面花的时间多,到后面就跟安了加速器一样~~~~好吧……
然后有点新认识。关于本题,给的是N*N的矩阵。原先以为有多少的移动对象,|G|就是多少……因为这道题还是一个二面体群,然后因为等价置换的操作仍旧是8种,所以|G|还是8,这是群的阶数。然后就是统计对于角的旋转,(90,180,270,360),统计关于两条对角线的翻转,关于对边中点连线的翻转,各两次。
关于角的旋转,我是用暴力算的。然后关于对角线的翻转,显然是每个循环都只有2个数,然后算出来是N*(N-1)/2,中线翻转的话,是floor((n+1)/2)。
唔……因为没有题解,所以也不知道自己想的对不对,先这样吧。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#define maxn 35
int f[2][maxn][maxn];
int tmp[maxn*maxn];
int vis[maxn*maxn];
using namespace std;
double sum;
int n,c;
void solve()
{
int i,j,k;
k=1;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
f[1][i][j]=k++;
int flag=1;
int len=0;
for(k=0;k<4;k++)
{
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
f[!flag][i][j]=f[flag][j][n-i+1];
tmp[(i-1)*n+j]=f[!flag][i][j];
// cout<<tmp[(i-1)*n+j]<<" ";
}
}
// cout<<endl;
int d=n*n;
memset(vis,0,sizeof(vis));
len=0;
int ans=0;
while(d)
{
int t=1;
while(vis[t]) t++;
int st=t;
while(1)
{
d--;
// cout<<t<<" ";
vis[t]=1;
t=tmp[t];
if(t==st) break;
}
len++;//cout<<endl;
}
// sum+=pow((double)c,len);
flag=!flag;
// printf("len=%d\n",len);
break;
// cout<<endl;
}
sum+=pow((double)c,4.0*len)+pow((double)c,2.0*len)+2*(double)c;
sum+=pow((double)c,(double)((n)*(n-1)/2))*2*pow((double)c,(double)n); ///两次,对角线翻转
double tt=floor((n+1)/2);
//cout<<"tt="<<tt<<endl;
sum+=pow((double)c,tt*n)*2; ///两次,对边中点连线翻转
sum/=8;
}
int main()
{
while(~scanf("%d%d",&n,&c))
{
sum=0;
int i,j,k;
//if(c==1) {cout<<1<<endl;continue;}
solve();
printf("%.lf\n",sum);
}
return 0;
}