题目链接:http://codeforces.com/problemset/problem/352/B
题目意思:给出一个长度为n的序列 a1, a2, ..., an(序号i,1 <= i <= n)。需要从这个序列中,找出符合这两个条件的数:1、这个数在序列 a1, a2, ..., an 中; 2、该数的所有位置(也就是序号i)构成等差数列。一旦有一个位置不满足(此时和上一个位置所求出的公差就与之前的公差不相等),这个数就不符合条件,不应该输出。找完之后,输出所有满足这两个条件的数的总数,还有这些数以及对应的公差。
值得注意的地方有:当这个数在序列中只出现一次的时候,也属于可输出的,此时它的公差为0,也就是ST 1的情况; 还有,整个序列一个都找不到这样的数,要输出0。
这条是我赛中第一次提交的,因为一下子就看懂题目了。不过赛中是没过到啦,以为很简单...赛后,修改,调试,整整两天多,终于AC了。方法比较笨,还是那句话,自己写的特别有感觉。后来看了别人用vector来做,代码长度缩短了很多。看来还是需要学一下容器啊~~~
方法一:
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <cstring> 6 using namespace std; 7 8 const int maxn = 1e5 + 5; 9 10 struct pairs 11 { 12 int index; // 保存位置的编号i 13 int num; // 保存序列的数,即题目中的a[i] 14 }p[maxn]; 15 16 int cmp(pairs a, pairs b) 17 { 18 if (a.num != b.num) 19 return a.num < b.num; 20 return a.index < b.index; // 关键!!!保证公差是正数,否则过不了test 10 21 } 22 23 int c[maxn], b[maxn]; 24 int f[maxn]; 25 26 int main() 27 { 28 int i, j, k, n, sum; 29 while (scanf("%d", &n) != EOF) 30 { 31 memset(c, 0, sizeof(c)); 32 for (j = i = 1; i <= n; i++) 33 { 34 scanf("%d", &p[i].num); 35 c[p[i].num]++; // 统计a[i]在序列中出现多少次 36 if (c[p[i].num] == 1) 37 { 38 b[j++] = p[i].num; // 保存a[i] 39 } 40 p[i].index = i; 41 } 42 k = j; 43 sort(p+1, p+n+1, cmp); // 序列a的数从小到大排序,如果相同,则按具体的位置从小到大排序 44 sort(b+1, b+j); // 保证输出的序列是递增的 45 /* for (i = 1; i <= n; i++) 46 { 47 printf("p[%d].index = %d, p[%d].num = %d\n", i, p[i].index, i, p[i].num); 48 } 49 */ 50 memset(f, 0, sizeof(f)); // 保存公差 51 int tmp, j, flag, minus; 52 sum = 0; 53 for (i = 1; i <= n; i += c[p[i].num]) 54 { 55 // printf("i = %d\n", i); 56 // printf("c[%d] = %d\n", p[i].num, c[p[i].num]); 57 if (c[p[i].num] == 1) // 在序列中只出现一次的数,公差设为0 58 { 59 f[p[i].num] = 0; 60 sum++; // 也属于可输出的 61 } 62 else 63 { 64 flag = 0; 65 for (j = i; j < c[p[i].num]+i-1; j++) // 检测相同数字的公差是否相等 66 { 67 // printf("j = %d\n", j); 68 if (j == i) // 用第一、二个的位置算出公差即可,下面用这个公差来检查其他位置的公差是否和这个公差相等 69 { 70 tmp = p[j+1].index - p[j].index; 71 // printf("tmp = %d\n", tmp); 72 } 73 minus = p[j+1].index - p[j].index; 74 // printf("minus = %d\n\n", minus); 75 if (tmp != minus) 76 { 77 f[p[i].num] = -1; // 发现有一个位置不等于之前算出的公差 78 flag = 1; 79 // printf("error !!!!\n\n"); 80 81 } 82 } 83 if (j == c[p[i].num]+i-1 && !flag) // 相同的数的所有位置算出的公差都相等 84 { 85 sum++; 86 // printf("success!!!\n"); 87 f[p[i].num] = tmp; // 保存公差 88 } 89 } 90 } 91 if (sum) 92 { 93 printf("%d\n", sum); // 符合条件的总数 94 for (i = 1; i < k; i++) 95 { 96 if (f[b[i]] != -1) 97 { 98 printf("%d %d\n", b[i], f[b[i]]); 99 } 100 } 101 } 102 else 103 printf("0\n"); 104 } 105 return 0; 106 }
方法二:
用vector方法写的,记得每次都要清空。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <vector> 6 using namespace std; 7 8 const int maxn = 1e5 + 5; 9 const int maxm = 5; 10 11 vector <int> s[maxn]; 12 int ans[maxn][maxm]; 13 14 int main() 15 { 16 int i, j, n, tmp, flag; 17 while (scanf("%d", &n) != EOF) 18 { 19 memset(s, 0, sizeof(s)); 20 for (i = 1; i <= n; i++) 21 { 22 scanf("%d", &tmp); 23 s[tmp].push_back(i); 24 } 25 int d, len, cnt = 0; 26 for (i = 1; i <= maxn; i++) 27 { 28 flag = 0; 29 len = s[i].size(); 30 if (len == 0) 31 continue; 32 else if (len == 1) 33 { 34 ans[cnt][0] = i; 35 ans[cnt][1] = 0; 36 cnt++; 37 } 38 else 39 { 40 d = s[i][1] - s[i][0]; 41 if (len == 2) 42 { 43 ans[cnt][0] = i; 44 ans[cnt][1] = d; 45 flag = 1; 46 cnt++; 47 } 48 // printf("d = %d\n", d); 49 if (!flag) 50 { 51 for (j = 2; j < len; j++) 52 { 53 if (s[i][j] - s[i][j-1] != d) 54 break; 55 } 56 if (j == len) 57 { 58 ans[cnt][0] = i; 59 ans[cnt][1] = d; 60 cnt++; 61 } 62 } 63 } 64 } 65 printf("%d\n", cnt); 66 for (i = 0; i < cnt; i++) 67 { 68 printf("%d %d\n", ans[i][0], ans[i][1]); 69 } 70 } 71 return 0; 72 }