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 (找規(guī)律)
題意:
給出一個圓的半徑 和 圓心的始末位置。每次操作只能繞圓周上的點旋轉若干角度。求該圓從初位置到末位置最少的操作次數。
分析:
不妨設圓的半徑為r,圓心在原點處。
先看只旋轉一次的情況,圓心所有可能位置構成的區(qū)域為 ?半徑為2r的圓(除去圓心那點),也可理解為半徑為(0, 2r]的圓環(huán)區(qū)域
再看第二次旋轉,其區(qū)域為半徑在(2r, 4r]的圓環(huán)區(qū)域?! ?/這個不容易畫圖,自行腦補一下好啦
以此類推。
算法:
所以我們可以先算出圓心始末位置間的距離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的完全二叉樹 和 一個目標葉子節(jié)點, 給出一種遍歷方式(LRLRLR...)
求在到達目標節(jié)點時,遍歷節(jié)點的總數。(不包括目標節(jié)點)
具體參見原文Guess Your Way Out!
分析:
以官方題解中的圖為例。自己最開始對這道題沒什么想法,所以后面的分析相當于題解的翻譯。=_=||
從樹根開始走到最底端,到達節(jié)點X。
如果X剛好是目標節(jié)點E,則得到結果為樹高h。
否則,找到X和E的?Least Common Ancestor (最小公共祖先)。在右子樹遍歷之前,一定會遍歷完左子樹中所有的節(jié)點 (圖中用紅色標出) ,從而退出,進入右子樹。
所以在到達右子樹之前共遍歷sum[h1] + h - h1,其中sum[h1]表示樹高為h1的完全二叉樹的節(jié)點個數。
在進入右子樹后,更新樹高h、根節(jié)點編號、遍歷的方向(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); //目標節(jié)點的所有祖先 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; //當前葉子節(jié)點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) //更新根節(jié)點的編號 及 遍歷方向 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 }代碼君
?
轉載于:https://www.cnblogs.com/AOQNRMGYXLMV/p/4249319.html
總結
以上是生活随笔為你收集整理的CodeForces Round #287 Div.2的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 最长公共子序列(LCS)问题 Lon
- 下一篇: displaytag 导出