codeforces B. Jeff and Periods 解题报告

本文探讨如何在给定序列中找到满足特定条件的数,即这些数在序列中的位置形成等差数列。文章提供了两种方法实现这一目标,并讨论了在不同情况下输出结果的策略。

题目链接: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来做,代码长度缩短了很多。看来还是需要学一下容器啊~~~

 

方法一:

    

TimeMemory

 

92 ms2000 KB

 

 

  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 }

 

方法二:

TimeMemory
92 ms4900 KB

用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 }

 

 

转载于:https://www.cnblogs.com/windysai/p/3354499.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值