几道数学题目

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只是用来输出字符串的,其他的也没查出什么区别

View Code
 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页有关于这道题目的详细解答

View Code
 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原理及其应用》

View Code
 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

View Code
 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 }

 

原文地址:https://www.cnblogs.com/fxh19911107/p/2517609.html