polya定理应用
来源:互联网 发布:新手淘宝开店教程 编辑:程序博客网 时间:2024/05/23 12:20
TT_last 原创,转载请注明。
polya定理不知道可先看潘震皓的 《置换群快速幂运算研究与探讨》,下面是根据论文所做的一些题目。
poj 2409
很裸的一道polya定理应用题目,
处理的状态有:一个点顺时针旋转 0 ~ n-1 个点
还有就是对称旋转的情况:
当n为偶数时:有两个对应的点相连线 和两条对应线段中点连线 分别形成的对称轴
当n为奇数时:仅有一个点与对应直线形成对称轴。
#include <iostream>#include <cmath>using namespace std;int c,s;int gcd(int a,int b){ if(b == 0) return a; else return gcd(b,a%b);}int polya(int n,int m){ int ans,i; __int64 tmp = 0; for(i = 0;i < n;i ++) { tmp += pow(m*1.0,1.0*gcd(n,i)); //n个循环 移动多少位。 } if(n&1) { tmp += n*pow(m*1.0,(n+1)/2.0); //n个循环 一个点与对应线段中点连线 }else { tmp += n/2*pow(m*1.0,n/2+1)+n/2*pow(m*1.0,n/2); //n个循环 分别为两个点连线 两条相对线段中点连线。 } ans = tmp/(2*n); return ans;}int main(){ while(scanf("%d%d",&c,&s),c|s) { printf("%d\n",polya(s,c)); } return 0;}
poj 2154
/*
欧拉函数 + 快速幂 + 筛选质因数
*/
原本n很大,如果按照前面的做法去做 从1 ~ n,不断枚举,那肯定要tle,这里需要用欧拉函数优化一下。
根据polya定理:方案数(先不考虑取余):
for(i = 0;i < n;i ++)
ans += pow(n,gcd(n,i));
从中,如果我们提取相同的gcd(n,i) 和取得它们的个数,那么时间复杂度将会减少很多。
设 m = gcd(n,i);m可以肯定是n的因子,而m = gcd(n,i),的个数就是 1 = gcd(n/m,i/m)的i/m个数,
这个可以用欧拉函数来求 euler(n/i);然后再根据polya定理做一下也就可以了。
#include <iostream>using namespace std;const int maxn = 32000;int n,m,tmp;int p[maxn],num,a[400],b[400],ans;bool sign[maxn];void init(){ int i,j; num = 0; p[num++] = 2; for(i = 4;i < maxn;i += 2) sign[i] = true; for(i = 3;i < maxn;i ++) { if(!sign[i]) { p[num++] = i; for(j = i*i;j < maxn;j += i) sign[j] = true; } }}void factor(int x){ int i; tmp = 0; for(i = 0;i < num;i ++) { if(x < p[i]) break; if(x%p[i] == 0) { b[tmp] = 0; while(x%p[i] == 0) { x /= p[i]; b[tmp]++; } a[tmp++] = p[i]; } } if(x > 1) b[tmp] = 1,a[tmp++] = x; }int euler(int x){ int ret = x,i; for(i = 0;i < num;i ++) { if(x < p[i]) break; if(x%p[i] == 0) { while(x%p[i] == 0) x /= p[i]; ret -= ret/p[i]; } } if(x > 1) ret -= ret/x; return ret;}int pow_m(int a,int b){ int ret = 1,t = a%m; while(b) { if(b&1) ret = (ret*t)%m; t = (t*t)%m; b >>= 1; } return ret;}void dfs(int dep,int sum){ int i,temp; if(dep == tmp) { ans = (ans + (euler(n/sum)%m)*pow_m(n,sum-1))%m; }else { for(i = 0,temp = 1;i <= b[dep];temp*=a[dep],i ++) dfs(dep+1,sum*temp); }}int main(){ int x; init(); scanf("%d",&x); while(x--) { scanf("%d%d",&n,&m); factor(n); ans = 0; dfs(0,1); printf("%d\n",ans); } return 0;}
poj 3270
/*置换群 最小交换权
第一种状态:polya循环中最小的那个数 去与其它数据交换。
费用: sum+(len-2)*min2;
第二种状态:从外面拿最小的数进来参与交换,最后换回去:
费用: sum+min2+(len+1)*min;
换进来 1 + 循环 len -1 + 出去 1 = len+1;
min2 出去1 + 进来 1 = 2;
*/
#include <iostream>#include <algorithm>using namespace std;const int inf = 1000000000;const int maxn = 10005;int v[maxn],b[maxn],n;int hash[maxn*10];bool sign[maxn];int main(){ int ans,min,min2,sum; int i,j,t,len; while(scanf("%d",&n)!=EOF) { min = inf; for(i = 0;i < n;i ++) { scanf("%d",&v[i]); b[i] = v[i]; sign[i] = false; if(min > v[i]) min = v[i]; } sort(b,b+n); for(i = 0;i < n;i ++) hash[b[i]] = i; ans = 0; for(i = 0;i < n;i ++) { if(!sign[i]) { t = i; min2 = v[i]; len = 0;sum = 0; sign[i] = true; do{ len ++; sum += v[t]; sign[t] = true; if(min2 > v[t]) min2 = v[t]; t = hash[v[t]]; }while(t != i); int ans1,ans2; ans1 = sum+(len-2)*min2; ans2 = sum+min2+(len+1)*min; ans += ans1 > ans2 ? ans2:ans1; } } printf("%d\n",ans); } return 0;}
poj 1026
题目是给出一个密钥,然后给出k和一段字符串,然后根据上面的密钥不处理字符串k次。处理的方法是:Character in the message at the position i is written in the encoded message at the position ai, where ai is the corresponding number in the key。
如果直接模拟肯定是tle的,我的做法是,先求出每一个循环,可以肯定每一个循环的周期就是那个循环的长度。
然后k%len[i] 得出每一个循环要做的处理次数,然后对于每一个循环都处理一下,最后输出结果就行了。
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int maxn = 205;int v[maxn],n,k,a[maxn],len[maxn],num;bool sign[maxn];char c[maxn];int main(){ int i,j,l,t; char tmp; //freopen("1.txt","w",stdout); while(scanf("%d",&n),n) { num = 0; len[0] = 0; for(i = 1;i <= n;i ++) { scanf("%d",&v[i]); sign[i] = false; len[i] = 0; } for(i = 1;i <= n;i ++) //求出每一个循环 的长度 和出发点。 { if(!sign[i]) { t = i; do { sign[t] = true; len[num] ++; t = v[t]; }while(t != i); a[num++] = i; } } while(scanf("%d",&k),k) { getchar(); gets(c+1); l = strlen(c+1); for(i = l+1;i <= n;i ++) c[i] = ' '; c[i] = '\0'; for(i = 0;i < num;i ++) //对每一个循环都进行k次变换,当然根据周期为len[num]取余 { l = k % len[i]; //进行l次循环。 复杂度最多 O(n^2) = 40000,可以接受。 for(j = 0;j < l;j ++) { t = a[i]; tmp = c[t]; do { swap(tmp,c[v[t]]); t = v[t]; }while(t != a[i]); } } puts(c+1); } puts(""); } return 0;}
poj 1721
论文后面的原题来的。将置换群用Jordan置换表示。
#include <iostream>using namespace std;const int maxn = 1005;int v[maxn],v2[maxn],n,s;int main(){ int i,j,t; while(scanf("%d%d",&n,&s)!=EOF) { for(i = 1;i <= n;i ++) scanf("%d",&v[i]); j = i = 1; v2[j] = 1; while(v[i] != 1) { v2[++j] = v[i]; i = v[i]; } t = 1; while(s > 0) { t = (t<<1)%n; s --; } v[1] = j = v2[1]; for(i = 2;i <= n;i ++) { j += t; if(j > n) j -= n; v[j] = v2[i]; } for(i = 1;i < n;i ++) v2[v[i]] = v[i+1]; v2[v[n]] = v[1]; for(i = 1;i <= n;i ++) printf("%d\n",v2[i]); } return 0;}
poj 3128
重要的句子:Write a program that takes a permutation of the English alphabet as input and decides if it may be the result of performing some permutation twice.
判断输入的句子能不能是某一个字串的平方。分两种情况:
当循环中有偶数个数的时候,平方后变成两个相等的循环。当循环奇数时,循环没有裂开。论文中gcd(i,n)可得。所以判断循环中相同数目的偶数循环是不是偶数,是的话就可以变成某个串的平方了。
#include <iostream>using namespace std;const int maxn = 30;bool sign[maxn];int n,a[maxn],num[maxn];char c[maxn];int main(){ int i,j,b; scanf("%d",&n); while(n--) { scanf("%s",c); for(i = 0;i < 26;i ++) a[i] = c[i] - 'A',sign[i] = false,num[i] = 0; num[26] = 0; for(i = 0;i < 26;i ++) { if(!sign[i]) { j = i; b = 0; do{ sign[j] = true; b ++; j = a[j]; }while(j != i); num[b] ++; } } for(i = 2;i <= 26;i +=2) if(num[i]%2) break; if(i <= 26) puts("No"); else puts("Yes"); } return 0;}
poj 3590
解题报告在:http://hi.baidu.com/zzningxp/blog/item/240fbc8ba9ee167a9e2fb428.html,参照着写就可以了。
#include <iostream>#include <algorithm>using namespace std;const int maxn = 200;int n;bool sign[maxn];int a[maxn],al,b[maxn],num,best[maxn],bl,ans,mul;void init(){ int i,j; b[num++] = 2; for(i = 2;i < maxn;i += 2) sign[i] = true; for(i = 3;i < maxn;i ++) { if(!sign[i]) { b[num++] = i; for(j = i*i;j < maxn;j += i) sign[j] = true; } }}void dfs(int sum,int i){ int j; if(sum < b[i]) { if(mul > ans) { ans = mul; for(j = 0;j < al;j ++) best[j] = a[j]; bl = al; while(sum > 0) { best[bl++] = 1; sum --; } } }else { dfs(sum,i+1); for(j = b[i];j <= sum;j *= b[i]) { a[al++] = j; mul *= j; dfs(sum - j,i+1); al --; mul /= j; } }}int main(){ int t,i,j,l; init(); scanf("%d",&t); while(t--) { al = bl = 0; ans = 0;mul = 1; scanf("%d",&n); if(n == 1) puts("1 1"); else { dfs(n,0); printf("%d",ans); sort(best,best+bl); for(i = 0,j = 1;i < bl;i ++) { for(l = j+1;l < j+best[i];l ++) printf(" %d",l); printf(" %d",j); j += best[i]; } printf("\n"); } }}
- polya定理应用
- Polya定理及应用
- POJ1286:Necklace of Beads(POLYA定理应用)
- polya定理
- polya定理
- polya定理
- Polya定理
- Polya定理
- polya 定理
- polya定理1286
- polya定理再小结
- Polya定理小结
- Polya定理,Burnside引理
- polya计数定理
- polya定理再小结
- POJ 2409 Polya定理
- poj 2409 polya定理
- Polya定理,Burnside引理
- 0.VC(ui)-hook-DrawItem挂掉
- 变换用户身份为root的方法su 与 sudo
- java设计模式连载(5) --单态模式
- Google收购Moto:天使还是魔鬼?
- VS2008 编译出现 error PRJ0003 : 生成 cmd.exe 时出错
- polya定理应用
- 平常生活之我见一
- jquery ui 编码文件造成的诡异问题
- iphone:圆角UITextView(和UITextField一样)
- 检测子进程的结束返回状态
- RPC Fault faultString="Cannot invoke method 'helloWorld'." faultCode="Server.ResourceUnavailable" fa
- 4*4 魔方阵
- VC2005做的EXE程序如何在没安装VS2005(FrameWork)的机器上运行?
- 菜鸟之驱动开发2