poj 1026 http://poj.org/problem?id=1026
题意:给你(乱序)数字,数字表示下面输入的字符串变幻的位置。比如说事例给的
10(n)
4 5 3 7 2 8 1 6 10 9
1(k) Hello Bob
1 代表对字符串中每一个字符进行变幻的次数。
变幻的方式就是
1 2 3 4 5 6 7 8 9 10(十个数排完序后)
H e l l o B o b
4 5 3 7 2 8 1 6 10 9
这样经过 1 次变幻后,H到第四个位置(也就是字符串下标为 3 的位置)e变幻到第 5 个位置,依次类推。当然,如果 k 不等于 1,例如 k = 4, H 的变幻路径为 4 -> 7 -> 1 -> 4
e的变幻路径为 2 -> 5 -> 2 -> 5 -> 2依次类推
思路:其实模拟就行了,但是要加一些优化,否则会超时的。从上面可以看出,因为答案只是让求出每个字符的最终位置,可以求出所给的n个数的每一个的循环次数,这样用k取余循环次数,可以减少很多不必要的操作
注意题目输出字符串时要求必须是 n 的长度,样例给的那个输出后面没有多余的空格,真是坑死人了。还有就是每个block后还要再输出一个空行,但是用puts输出就会PE,用printf输出就AC了,上网查了一下区别,只是说puts只是用来输出字符串的,其他的也没查出什么区别
1 #include <iostream> 2 #include <math.h> 3 #include <cstdio> 4 #include <algorithm> 5 #include <string.h> 6 #define N 210 7 #define _clr(a,val) (memset(a,val,sizeof(a))) 8 9 using namespace std; 10 11 int tkey[N],key[N]; 12 int tind[N]; //用来保存每个数的循环次数 13 int tem[N],v[N];// v[i]标记是否已经被计算过,因为在一个循环内的数的循环数是相等的,tem[i]用来记录一个循环内的编号 14 char str[N],sbr[N]; 15 int cnt; 16 void get_next(int n) 17 { 18 int i,sum,j; 19 int cnt; 20 _clr(v,0); 21 for(i = 0; i < n; i++) 22 { 23 if(!v[i]) 24 { 25 for(j = 0; j < n; j++) 26 tem[j] = 0; 27 v[i] = 1; 28 j = i; 29 sum = 1; 30 cnt = 0; 31 while(tkey[i] != key[j]) // 求循环数 32 { 33 sum++; 34 tem[cnt++] = j; 35 v[j] = 1; 36 j = key[j] - 1; 37 } 38 v[j] = 1; 39 tem[cnt++] = j; 40 for(j = 0; j < cnt; j++) 41 tind[tem[j]] = sum; 42 } 43 } 44 } 45 void chang(int n,int k) 46 { 47 _clr(sbr,0); 48 int i,j,len; 49 int temp; 50 len = strlen(str); 51 if(len < n) 52 for(i = len; i < n; i++) 53 str[i] = ' '; 54 str[i] = '\0'; 55 for(i = 0; i < n; i++) 56 { 57 if(k == 1) temp = 1; 58 else temp = k % tind[i]; 59 j = i; 60 while(temp > 0) 61 { 62 if(tkey[i] == key[j]) temp--; //循环数为 1 时做的处理 63 while(tkey[i] != key[j]) // 查找最终的位置 64 { 65 temp --; 66 j = key[j] - 1; 67 if(!temp) break; 68 } 69 } 70 sbr[j] = str[i]; 71 } 72 cout<<sbr<<endl; 73 } 74 int main() 75 { 76 int n,i,k; 77 //freopen("data.txt","r",stdin); 78 while(scanf("%d",&n),n) 79 { 80 for(i = 0; i < n; i++) 81 { 82 scanf("%d",&key[i]); 83 tkey[i] = key[i]; 84 } 85 sort(tkey,tkey + n); 86 get_next(n); 87 while(scanf("%d",&k),k) 88 { 89 getchar(); 90 gets(str); 91 chang(n,k); 92 } 93 //puts("\n"); // 用puts结果总是PE,用printf就AC了 94 printf("\n"); 95 } 96 return 0; 97 }
poj 3270 http://poj.org/problem?id=3270
题意:给出一个含有n 个数的序列,n个数中任意两个可以调换位置,使得目标序列为递增序列,调换位置付出的代价是两个数的和,怎样才能使得总代价最小,输出最小代价值
刘汝佳 黑书 248页有关于这道题目的详细解答
1 #include <cstdio> 2 #include <cmath> 3 #include <cstring> 4 #include <algorithm> 5 #include <iostream> 6 #define _clr(a,val) (memset(a,val,sizeof(a))) 7 #define N 10005 8 #define inf 100001 9 10 using namespace std; 11 12 int cow[N],v[N],tcow[N]; 13 int ind[inf]; 14 int main() 15 { 16 int n,i,j,k; 17 int sum,minn,ans; 18 int tem; 19 //freopen("data.txt","r",stdin); 20 while(scanf("%d",&n) != EOF) 21 { 22 //minn = inf; 23 /*for(i = 0; i < n; i++) 24 { 25 v[i] = 0; 26 ind[i] = 0; 27 }*/ 28 for(i = 0; i < n; i++) 29 { 30 scanf("%d",&cow[i]); 31 //if(cow[i] < minn) minn = cow[i]; 32 tcow[i] = cow[i]; 33 v[i] = ind[i] = 0; 34 } 35 sort(tcow, tcow + n); 36 minn = tcow[0]; 37 for(i = 0; i < n; i++) 38 { 39 ind[tcow[i]] = i; 40 } 41 ans = 0; 42 for(i = 0; i < n; i++) 43 { 44 if(!v[i]) 45 { 46 sum = 0; 47 tem = tcow[i]; 48 j = i, k = 1; 49 v[j] = 1; 50 while(tcow[i] != cow[j]) 51 { 52 sum += cow[j]; 53 j = ind[cow[j]]; 54 v[j] = 1; 55 k++; 56 } 57 if(k > 1) 58 { 59 ans += min(sum + (k - 1) * tem,sum + (k - 1) * minn + 2 * (tem + minn)); 60 } 61 } 62 } 63 printf("%d\n",ans); 64 } 65 return 0; 66 }
poj 2409 http://poj.org/problem?id=2409
题意:给你 c 种颜色,s 个弹珠,问可以串出几种不同的手镯。
如果做了poj 的 1286,再来做这道题目,就会觉得很简单了,因为只需改一下输入和计算时用的参数就可以了。 这两道题目是polya定理,置换群的应用中最裸的题目,关键就是如何找每个置换群的循环节数,我也是看的别人的解题报告,知道的如何找循环节数。给出两个参考链接,结合这看,应该是可以能够理解,http://www.cnblogs.com/yongze103/archive/2010/10/05/1842936.html http://blog.sina.com.cn/s/blog_64d591e80100h8be.html。不过如果想知道那个公式怎么来的,有兴趣的可以去看 组合数学 第四版,或是 符文杰:《Pólya原理及其应用》
1 #include <iostream> 2 #include <string.h> 3 #include <math.h> 4 #include <stdio.h> 5 #include <algorithm> 6 7 using namespace std; 8 9 int gcd(int a,int b) 10 { 11 if(!b) return a; 12 else return gcd(b,a % b); 13 } 14 int main() 15 { 16 int n,i,m; 17 long long sum; 18 //freopen("data.txt","r",stdin); 19 while(cin>>m>>n,n + m) 20 { 21 sum = 0; 22 if(!n) 23 { 24 cout<<"0\n";continue; 25 } 26 for(i = 1; i <= n; i++) 27 { 28 sum += (pow(1.0 * m,gcd(n,i))); 29 } 30 if(n % 2 == 0) 31 { 32 sum += ((pow(1.0 * m, n / 2 ) * (n / 2))); 33 sum += ((pow(1.0 * m, (n + 2) / 2) * (n / 2))); 34 } 35 else sum += ((pow(1.0 * m, (n + 2) / 2) * n)); 36 sum = sum / (2 * n); 37 printf("%lld\n",sum); 38 } 39 return 0; 40 }
poj 1286 http://poj.org/problem?id=1286
1 #include <iostream> 2 #include <string.h> 3 #include <math.h> 4 #include <stdio.h> 5 #include <algorithm> 6 7 using namespace std; 8 9 int gcd(int a,int b) 10 { 11 if(!b) return a; 12 else return gcd(b,a % b); 13 } 14 int main() 15 { 16 int n,i; 17 long long sum; 18 //freopen("data.txt","r",stdin); 19 while(cin>>n,n != -1) 20 { 21 sum = 0; 22 if(!n) 23 { 24 cout<<"0\n";continue; 25 } 26 for(i = 1; i <= n; i++) 27 { 28 sum += (pow(3.0,gcd(n,i))); 29 } 30 if(n % 2 == 0) 31 { 32 sum += ((pow(3.0, n / 2 ) * (n / 2))); 33 sum += ((pow(3.0, (n + 2) / 2) * (n / 2))); 34 } 35 else sum += ((pow(3.0, (n + 2) / 2) * n)); 36 sum = sum / (2 * n); 37 printf("%lld\n",sum); 38 } 39 return 0; 40 }