AtCoder Regular Contest 112 (3 / 6)

A、A - B = C

题目:给定L、R,求问存在多少个A、B、C三元组,使得A=B+C,其中L <= A <= R, L <= B <= R, L <= C <= R

答案:针对一个固定的A,存在满足条件的(B、C)两元组的数量为 A - 2 * L + 1,所以当你遍历A时,答案为一个等差数列,最小值=1,最大值=R - 2 * L + 1,差=1,则对等差数列求和即可。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn = 1e6 + 7;
 5 const ll mod = 1e9 + 7;
 6  
 7 int main()
 8 {
 9     int t;
10     cin >> t;
11     while(t--){
12         int l, r;
13         cin >> l >> r;
14         ll ans = max(0, (r - 2 * l + 2)) * 1LL * max(0, (r - 2 * l + 1)) / 2;
15         cout << ans << "
";
16     }
17     return 0;
18 }
View Code

B、B - -- - B

题目:你有一个数字B 和 C 元钱,你可以做如下两种操作:1)花费1元对数字B乘以-1,2)花费2元对数字B减去1,问你最终有可能得到多少个数字。

答案:针对B,你可以一直减1,扩大在坐标轴上左边的范围;还可以先*-1,再不断减,扩大范围。针对你在坐标轴左右两侧的每一侧,你都可以获得一定的可达范围,那么同时你也可以*-1,获得同绝对值下的另一端的范围。最终你会发现,B两侧相距 C / 2的点都可以达到,对0点求对称,坐标轴另一侧可以达到,大概距离为 C / 2 * 2 * 2,再考虑不同情况去重即可。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn = 1e6 + 7;
 5 const ll mod = 1e9 + 7;
 6  
 7 int main()
 8 {
 9     ll b, c;
10     cin >> b >> c;
11     ll ans = 0, l, r;
12     if(b > 0){
13         if(b - (c / 2) > 0){
14             ans += c / 2 * 2 + 2;
15             if(c > 0 && c % 2 == 0)--ans;
16             --c;
17             ans += c / 2 * 2;
18             if(c > 0 && c % 2 == 0)--ans;
19         }
20         else{
21             ans += b * 2 + 1;
22             --c;
23             ans += c / 2 * 2;
24             if(c > 0 && c % 2 == 0)--ans;
25         }
26     }
27     else{
28         ans += c / 2 * 2 + 2;
29         if(c > 0 && c % 2 == 0)--ans;
30         if((c - 1) / 2 >= b * -1)ans += b * -1 * 2 - 1;
31         else{
32             ans += (c - 1) / 2 * 2;
33             if((c - 1) % 2 == 0)--ans;
34         }
35     }
36     cout << ans << "
";
37     return 0;
38 }
View Code

C、DFS Game

题目:题目是个游戏,比较负责,就不翻译了。https://atcoder.jp/contests/arc112/tasks/arc112_c

答案:主要难点在于针对不同子树遍历的优先级选择上,即最先选择哪颗子树去遍历;每颗子树有两个属性是可以提前求得的:1)遍历完该子树之后选择权是否会转移,2)遍历完该子树会相会少获得几个coin;那么遍历的优先级如下

1、当损失都为负值时,即遍历该树能赚,那么优先考虑遍历完选择权不会转移的子树(因为选择权不转移,下次还可以继续优选选择),即损失为偶数的子树(损失为偶数,代表遍历完选择权不会转移,反之亦然)
2、当损失一负一正时,优先考虑负值,因为负值可以获得正加权,即能赚
3、当损失两正时,优先考虑奇数,即选择权转化,因为要下次把锅刷给对方(锅就代表遍历完子树是吃亏的)
4、当损失为正数且同奇偶性时,先考虑小值,尽量少损失一些

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn = 1e6 + 7;
 5 const ll mod = 1e9 + 7;
 6  
 7 vector<int> v[maxn];
 8 bool comp(pair<int, int> x, pair<int, int> y){
 9     int a = x.first, b = y.first;
10     if(a < 0 || b < 0){
11         if(a < 0 && b < 0 && a % 2 != b % 2){
12             return a % 2 == 0;
13         }
14         return a < b;
15     }
16     if(a % 2 != b % 2){
17         return a % 2 == 1;
18     }
19     return a < b;
20 }
21 pair<int, int> dfs(int x, int pre = 0){
22     vector<pair<int, int>> vn;
23     for(int y: v[x]){
24         pair<int, int> now = dfs(y);
25         vn.push_back(now);
26     }
27     sort(vn.begin(), vn.end(), comp);
28     int a[2], ins = 0;
29     a[0] = 1;
30     a[1] = 0;
31     //cout << "x = " << x << '
';
32     for(pair<int, int> tmp: vn){
33         int x = tmp.first, y = tmp.second;
34         //cout << ins << " " << x << " " << y << " " << y - x << " " << a[0] << " " << a[1] << "
";
35         a[ins] += y;
36         a[ins ^ 1] += y - x;
37         if(x % 2 != 0){
38             ins ^= 1;
39         }
40     }
41     //cout << "x = " << x << " " << a[0] - a[1] << " " << a[0] << " " << a[1] << "
";
42     return make_pair(a[0] - a[1], a[0]);
43 }
44 int main()
45 {
46     int n;
47     cin >> n;
48     for(int i = 2; i <= n; ++i){
49         int x;
50         cin >> x;
51         v[x].push_back(i);
52     }
53     pair<int, int> ans = dfs(1);
54     cout << ans.second << "
";
55     return 0;
56 }
View Code
原文地址:https://www.cnblogs.com/wa007/p/14401257.html