CodeForces Round #287 Div.2

A. Amr and Music (贪心)

水题,没能秒切,略尴尬。

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4
 5 const int maxn = 100 +10;
 6 int a[maxn], r[maxn], ans[maxn];
 7
 8 int cmp(int i, int j) { return a[i] < a[j]; }
 9
10 int main()
11 {
12     //freopen("in.txt", "r", stdin);
13
14     int n, k;
15     scanf("%d%d", &n, &k);
16     for(int i = 0; i < n; ++i) r[i] = i;
17     for(int i = 0; i < n; ++i) scanf("%d", &a[i]);
18     sort(r, r + n, cmp);
19     int sum = 0, cnt = 0;
20     for(int i = 0; sum + a[r[i]] <= k && cnt < n; ++i)
21     {
22         sum += a[r[i]];
23         ans[cnt++] = r[i];
24     }
25
26     printf("%d\n", cnt);
27     for(int i = 0; i < cnt - 1; ++i) printf("%d ", ans[i]+1);
28     if(cnt) printf("%d\n", ans[cnt-1]+1);
29
30     return 0;
31 }

代码君

B. Amr and Pins (找规律)

题意:

给出一个圆的半径 和 圆心的始末位置。每次操作只能绕圆周上的点旋转若干角度。求该圆从初位置到末位置最少的操作次数。

分析:

不妨设圆的半径为r,圆心在原点处。

先看只旋转一次的情况,圆心所有可能位置构成的区域为  半径为2r的圆(除去圆心那点),也可理解为半径为(0, 2r]的圆环区域

再看第二次旋转,其区域为半径在(2r, 4r]的圆环区域。  //这个不容易画图,自行脑补一下好啦

以此类推。

算法:

所以我们可以先算出圆心始末位置间的距离d,然后根据d和直径2r的关系,最终答案为

 1 #include <cstdio>
 2 #include <cmath>
 3
 4 int main()
 5 {
 6     //freopen("in.txt", "r", stdin);
 7
 8     int r, x1, y1, x2, y2, ans;
 9     scanf("%d%d%d%d%d", &r, &x1, &y1, &x2, &y2);
10     double d = sqrt((long long)(x1-x2)*(x1-x2) + (long long)(y1-y2)*(y1-y2));
11     ans = (int)ceil(d / 2.0 / r);
12     printf("%d\n", ans);
13
14     return 0;
15 }

代码君

C. Guess Your Way Out! (模拟 LCA)

题意:

有一个树高为h的完全二叉树 和 一个目标叶子节点, 给出一种遍历方式(LRLRLR...)

求在到达目标节点时,遍历节点的总数。(不包括目标节点)

具体参见原文Guess Your Way Out!

分析:

以官方题解中的图为例。自己最开始对这道题没什么想法,所以后面的分析相当于题解的翻译。=_=||

从树根开始走到最底端,到达节点X。

如果X刚好是目标节点E,则得到结果为树高h。

否则,找到X和E的 Least Common Ancestor (最小公共祖先)。在右子树遍历之前,一定会遍历完左子树中所有的节点 (图中用红色标出) ,从而退出,进入右子树。

所以在到达右子树之前共遍历sum[h1] + h - h1,其中sum[h1]表示树高为h1的完全二叉树的节点个数。

在进入右子树后,更新树高h、根节点编号、遍历的方向(L or R),重复刚才的过程。

 1 #include <cstdio>
 2 #include <vector>
 3 #include <algorithm>
 4 using namespace std;
 5
 6 typedef long long LL;
 7
 8 LL h, n, sum[55], ans = 0;
 9 vector<LL> anc1;
10
11 int main()
12 {
13     //freopen("in.txt", "r", stdin);
14
15     for(int i = 0; i <= 50; ++i) sum[i] = (1LL << (i+1)) - 1;
16     scanf("%I64d%I64d", &h, &n);
17     n += sum[h-1];  //转化成整个二叉树中的编号
18     LL x = n;
19     anc1.push_back(x);  //目标节点的所有祖先
20     while(x != 1)
21     {
22         x /= 2;
23         anc1.push_back(x);
24     }
25     //for(int i = 0; i < anc1.size(); ++i) printf("%I64d  ", anc1[i]);
26
27     LL node = 1;
28     bool choice = false;    //遍历防线(L or R)
29
30     while(node != n)
31     {
32         vector<LL> anc2;    //当前叶子节点X的祖先
33         for(int i = 0; i < h; ++i)
34         {
35             anc2.push_back(node);
36             if(!choice) node = node * 2; else node = node * 2 + 1;
37             choice = !choice;
38         }
39         if(n == node) { ans += h; break; }
40         anc2.push_back(node);
41         reverse(anc2.begin(), anc2.end());
42         //for(int i = 0; i < anc2.size(); ++i) printf("%I64d  ", anc2[i]);
43
44         for(int i = 1; i <= h; ++i) if(anc1[i] == anc2[i])
45         {//find LCA
46             ans += sum[i-1] + h - i + 1;
47             h = i - 1;      //更新树高
48             node = anc2[i-1];
49             if((anc2[i]<<1) == node)    //更新根节点的编号 及 遍历方向
50             {
51                 node = anc2[i] * 2 + 1;
52                 choice = false;
53             }
54             else
55             {
56                 node = (anc2[i] << 1);
57                 choice = true;
58             }
59             break;
60         }
61     }
62
63     printf("%I64d\n", ans);
64
65     return 0;
66 }

代码君

时间: 2024-12-22 11:13:20

CodeForces Round #287 Div.2的相关文章

Codeforces Round #287 (Div. 2) ABCDE

A题.. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <cmath> 6 #include <vector> 7 8 using namespace std; 9 10 #define LL long long 11 #define eps 1e-8 12 #define inf 0x3

Codeforces Round #287 (Div. 2)A,B,C,D,E

A签到题排序之后贪心一下就可以了. const int maxn = 10010; using namespace std; struct node { int pos; int num; }f[maxn]; bool cmp(node a, node b) { return a.num < b.num; } int p[maxn]; int main() { int n, k; while(cin >>n>>k) { for(int i = 0; i < n; i++

Codeforces Round #287 (Div. 2) A、B、C、D、E

A:签到题,排序判断一下能学几门即可 B:圆心可以每步可以移动2 * r的距离,方向任选,所以答案是ceil(两点距离 / 2 / r) C:递归下去就可以了,dfs(h, n, flag),h表示当前到哪层,n表示当前层下的出口相对位置,flag表示下一步往左还是往右 D:数位DP,从最低位往最高位去放数字,如果一旦出现取模为0,就可以直接计算种数位后面还剩多少位,最后一位可以放1-9,其他都是0-9,不然就继续记忆化搜下去 E:最短路,把图建起来,假设1边总数为x,选择的路径上1边数位a,0

Codeforces Round #287 (Div. 2)C. Guess Your Way Out!

Amr bought a new video game "Guess Your Way Out!". The goal of the game is to find an exit from the maze that looks like a perfect binary tree of height h. The player is initially standing at the root of the tree and the exit from the tree is lo

Codeforces Round #287 (Div. 2) 解题报告 A.B.C.D.E

这次的CF挺水的,当时B题犯了一个很SB的错误,浪费了好多时间,所以D和E也没来得及看.sad,.. A - Amr and Music 水题,从小的开始选. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #include <map&

Codeforces Round #287 (Div. 2) 解题报告

好久没写题了,底下代码都比较糟糕,将就着看吧.. 507A  Amr and Music 要学最多的乐器,所以我们贪心选择时间花费少的.注意这里可以直接用pair,就不必写struct的compare函数了 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 struct ins{ 7 int v, id; 8 } a[110]; 9 bool c

Codeforces Round #279 (Div. 2) ABCD

Codeforces Round #279 (Div. 2) 做得我都变绿了! Problems # Name     A Team Olympiad standard input/output 1 s, 256 MB  x2377 B Queue standard input/output 2 s, 256 MB  x1250 C Hacking Cypher standard input/output 1 s, 256 MB  x740 D Chocolate standard input/

Codeforces Round #428 (Div. 2)

Codeforces Round #428 (Div. 2) A    看懂题目意思就知道做了 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b; i>=a; --i

Codeforces Round #424 (Div. 2) D. Office Keys(dp)

题目链接:Codeforces Round #424 (Div. 2) D. Office Keys 题意: 在一条轴上有n个人,和m个钥匙,门在s位置. 现在每个人走单位距离需要单位时间. 每个钥匙只能被一个人拿. 求全部的人拿到钥匙并且走到门的最短时间. 题解: 显然没有交叉的情况,因为如果交叉的话可能不是最优解. 然后考虑dp[i][j]表示第i个人拿了第j把钥匙,然后 dp[i][j]=max(val(i,j),min(dp[i-1][i-1~j]))   val(i,j)表示第i个人拿