Codeforces Round #312 (Div. 2)

A. Lala Land and Apple Trees

题目描述:

  一条坐标轴,在坐标轴上散布了一些苹果树,每棵树都有位置和所结果实数目两个属性,Amr在坐标轴0点的位置,Amr在开始的时候可以选择向左或者右走,然后遇到果树才能改变方向,问最后最多能拿到多少个苹果?

解题思路:

  开两个数组,分别代表坐标正半轴和负半轴,然后对每个数组排下一序,刚开始选择苹果树多的方向,然后累加就好。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 struct node
 4 {
 5     int x, y;
 6 };
 7 const int maxn = 110;
 8 node x[maxn], y[maxn];
 9 int cmp (const void *a, const void *b)
10 {
11     node *c = (node *)a;
12     node *d = (node *)b;
13     return c->x - d->x;
14 }//按照a[i].x升序排列
15 int main ()
16 {
17     int n;
18     while (scanf ("%d", &n) != EOF)
19     {
20         int a, b, i, j;
21         i = j = 0;
22         for (int k=0; k<n; k++)
23         {
24             scanf ("%d %d", &a, &b);
25             if(a < 0)
26             {
27                 x[i].x = -a;//注意负数的时候要降序排
28                 x[i ++].y = b;
29             }
30             else
31             {
32                 y[j].x = a;
33                 y[j++].y = b;
34             }
35         }
36         qsort (x, i, sizeof(x[0]), cmp);
37         qsort (y, j, sizeof(y[0]), cmp);
38         if (i < j)
39             j = i + 1;
40         else if (j < i)
41             i = j + 1;
42         int sum = 0;
43         for (int k =0; k<i; k++)
44             sum += x[k].y;
45         for (int k=0; k<j; k++)
46             sum += y[k].y;
47         printf ("%d\n", sum);
48     }
49     return 0;
50 }
View Code

B. Amr and The Large Array

题目描述:

  给出n个数字,求出在这n个数中用最小的区间包含全部出现次数最多的数,输出此区间下标,如果有多个输出任意一个。

解题思路:

  用hash存储,就用不上排序了,并且处理起来也方便,复杂度也低。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 struct node
 4 {
 5     int x, y, z;
 6 };
 7 const int maxn = 1000010;
 8 node x[maxn];//x[i].x——i出现的数目,x[i].y——i出现的最小下标,x[i].z——i出现的最大下标
 9 int main ()
10 {
11     int n;
12     while (scanf ("%d", &n) != EOF)
13     {
14         int a, b, Max = 0;
15         memset (x, 0, sizeof(x));
16         for (int i=1; i<=n; i++)
17         {
18             int num;
19             scanf ("%d", &num);
20             x[num].x++;
21             if (i < x[num].y || x[num].y == 0)
22                 x[num].y = i;
23             if (i > x[num].z)
24                 x[num].z = i;
25             if (x[num].x > Max || (x[num].x == Max && x[num].z - x[num].y < b - a))
26             {
27                 Max = x[num].x;
28                 a = x[num].y;
29                 b = x[num].z;
30             }
31         }
32         printf ("%d %d\n", a, b);
33     }
34     return 0;
35 }
View Code

C. Amr and Chemistry

题目描述:

  给出n个数字,对每一个数字有两个操作,分别是左移一位或者是右移一位,问至少多少次操作才能把这n个数变的相同?

解题思路:

  因为数据范围不太大,可以把每一个数通过这两个操作可以转出来的数和至少需要操作的次数记录下来,然后比较最小。

  在记录的时候因为偶数右移一位后,再进行左移不会变化,但是奇数就会变化。

  所以对于每一个数字先进行左移操作直到变为最大,再对这个数字进行右移操作,直到遇到奇数后再一直进行左移操作。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 100010;
 4 const int INF = 0x3f3f3f3f;
 5 struct node
 6 {
 7     int x, y;
 8 };
 9 node stu[maxn];
10 int num[maxn];
11 int main ()
12 {
13     int n, Max;
14     while (scanf ("%d", &n) != EOF)
15     {
16         memset (stu, 0, sizeof(stu));
17         Max = 0;
18         for (int i=0; i<n; i++)
19         {
20             scanf ("%d", &num[i]);
21             Max = max(Max, num[i]);
22         }
23         for (int i=0; i<n; i++)
24         {
25             int j = 0;
26             while (num[i])
27             {
28                 int k = j;
29                 for (int tem=num[i]; tem<=Max; tem*=2)
30                 {
31                     stu[tem].x ++;
32                     stu[tem].y += k;
33                     k ++;
34                 }
35                 while (num[i])
36                 {
37                     int tem = num[i];
38                     num[i] /= 2;
39                     j ++;
40                     if (tem != num[i]*2)
41                         break;
42                     stu[num[i]].x ++;
43                     stu[num[i]].y += j;
44 
45                 }
46             }
47         }
48         int sum = INF;
49         for (int i=1; i<=Max; i++)
50             if (stu[i].x == n && stu[i].y < sum)
51                 sum = stu[i].y;
52         printf ("%d\n", sum);
53     }
54     return 0;
55 }
View Code

 D. Guess Your Way Out! II

题目描述:

  有一颗深度为n的完全二叉树,树根标记为1,i节点的左儿子标记为2*i,右儿子标记为2*i+1。Amr要从根节点走到叶子节点(众多的叶子节点中只有一个出口),Amr为了走出出口,可以提出问题,系统会回答“YES”或者“NO”,给出问题和答案清单,问Amr是否可以根据这些问题和答案找到出口?

解题思路:

  输出的答案一共有三种:

  1:可以判断出唯一出口,输出出口的节点编号。

  2: 找出了多个出口,就输出“Data not sufficient!

  3: 如果答案之间相互矛盾,就输出“Game cheated!”(最后任何一个节点都不可能为出口或者出口可能同时出现在两个区间

  我们可以先根据问题给出存在出口的区间进行筛选,最终找出出口可能所在的区间,出口可能同时出现在两个区间的话输出“Game cheated!”,同时把不存在出口的区间记录下来,枚举保存到的区间在可能存在的区间里面去掉。遍历完了以后呢,如果不存在叶子节点就证明游戏是骗人的,存在多个的话就是信息不够多,唯一一个才是真爱。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 typedef __int64 LL;
  4 const int maxn = 100010;
  5 struct node
  6 {
  7     LL l, r;
  8 }stu[maxn];
  9 vector <node> vec;
 10 bool cmp (node a, node b)
 11 {//按照区间起始点升序,大区间排前面
 12     if (a.l == b.l)
 13         return a.r > b.r;
 14     return a.l < b.l;
 15 }
 16 int main ()
 17 {
 18     LL h, q, L, R, left, right;
 19     LL ans, level, cnt = 0, flag = 1;
 20     scanf ("%I64d %I64d", &h, &q);
 21     L = 1LL << (h-1);//所给完全二叉树的所有叶子节点区间
 22     R = (1LL << h) - 1;
 23     while (q --)
 24     {
 25         scanf ("%I64d %I64d %I64d %I64d", &level, &left, &right, &ans);
 26         if (!flag)
 27             continue;
 28         LL l = left << (h - level);
 29         LL r = ((right + 1) << (h - level)) - 1;
 30         if (!ans)
 31         {
 32             stu[cnt].l = l;
 33             stu[cnt++].r = r;
 34         }
 35         else
 36         {
 37             if (L>r || R<l)
 38                 flag = 0;
 39             else
 40             {//合并区间
 41                 L = max (L, l);
 42                 R = min (R, r);
 43             }
 44         }
 45     }
 46     if (!flag)
 47     {
 48         printf ("Game cheated!\n");
 49         return 0;
 50     }
 51     sort (stu, stu+cnt, cmp);
 52     vec.clear();
 53     for (int i=0; i<cnt; i++)
 54     {
 55         LL l = stu[i].l;
 56         LL r = stu[i].r;
 57         if (L > R || R < l)
 58             break;//合法区间为空||所剩不合法区间在合法区间后面并且两着无交集
 59         if (r < L)//枚举到得不合法区间在合法区间前面并且两着无交集
 60             continue;
 61         if (l<=L && R<=r)
 62         {//不合法区间包括合法区间
 63             flag = 0;
 64             break;
 65         }
 66         if (L<=l && r<=R)
 67         {
 68             node p;
 69             p.l = L;
 70             p.r = l-1;
 71             if (p.l <= p.r)
 72                 vec.push_back(p);
 73             L = r + 1;
 74             continue;
 75         }
 76         if (l<=R && R<=r)
 77         {//不合法区间与合法区间交于合法区间后面
 78             node p;
 79             p.l = L;
 80             p.r = l-1;
 81             if (p.l <= p.r)
 82                 vec.push_back(p);
 83                 flag = 0;//这里很重要
 84             break;
 85         }
 86         if (l<=L && L<=r)
 87         {
 88             L = r + 1;
 89         }
 90     }
 91     if (flag && L<=R)
 92     {//两个条件要同时成立
 93         node p;
 94         p.l = L;
 95         p.r = R;
 96         vec.push_back(p);
 97     }
 98     if (vec.size() == 0)
 99         printf ("Game cheated!\n");
100     else if (vec.size()>1 || (vec.size()==1 && vec[0].l!=vec[0].r))
101         printf ("Data not sufficient!\n");
102     else
103         printf ("%I64d\n", vec[0].l);
104     return 0;
105 }
View Code

 

转载于:https://www.cnblogs.com/alihenaixiao/p/4647300.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值