训练赛13+14

训练赛13

A - Amsopoly Simple Version    Gym - 102279A

题目大意:三人轮流掷骰子玩大富翁游戏,具体的游戏地图如下图。每人移动点数是固定的,移动到空格占领,自己的格子无事,别人的格子交罚款。问出现有人交罚款时,三人一共移动了多少次。

若永远不会有人被罚款,则输出3000000000。

 思路:移动占领直接模拟,主要问题是在如何判断永远不会罚款的情况。我的做法是当他们三人都走过自己之前占领过的格子时,若还没人被罚款,就一定不会有人被罚款了。

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int k[100010];
 4 int main() {
 5     std::ios::sync_with_stdio(false);
 6     int n, v1, v2, v3,ans=0,flag1=0,a=0,b=0,c=0,flag2=0,flag3=0;
 7     cin >> n >> v1 >> v2 >> v3;
 8     n++;
 9     while (flag1==0||flag2==0||flag3==0) {
10         a = (a + v1) % n;
11         ans++;
12         if (a > 0) {
13             if (k[a] == 2 || k[a] == 3)break;
14             else if (k[a] == 1)flag1 = 1;
15             else if (k[a] == 0)k[a] = 1;
16         }
17         b = (b + v2) % n;
18         ans++;
19         if (b > 0) {
20             if (k[b] == 1 || k[b] == 3)break;
21             else if (k[b] == 2)flag2 = 1;
22             else if (k[b] == 0)k[b] = 2;
23         }
24         c = (c + v3) % n;
25         ans++;
26         if (c > 0) {
27             if (k[c] == 1 || k[c] == 2)break;
28             else if (k[c] == 3)flag3 = 1;
29             else if (k[c] == 0)k[c] = 3;
30         }
31     }
32     if (flag1 == 1 && flag2 == 1 && flag3 == 1)cout << "3000000000" << endl;
33     else cout << ans << endl;
34     return 0;
35 }

D - Dahlia The Champion     Gym - 102279D

题目大意:游戏里的一个角色,技能是钩向任一方向直线上的第一个目标,现在给出技能范围、n个目标和它们的笛卡尔坐标,求有多少目标会被钩中。

思路:挺烦的一道题。将目标坐标用目标位置和施法位置的差来表示,消除如果施法位置不在原点难以比较的问题。其次,即使两点在同一直线上,如果它们分别处于施法位置的两侧,那么都可以钩到,

          因此,可以用x表示目标所在正负方向,y表示所在直线斜率;特别地,x=0时求斜率会出现除零错误,可以将斜率设为一个很大的值。最后结构体排序扫一遍就好了。

代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 long long b[500001], c[500001];
 4 struct node {
 5     double x, y;
 6 };
 7 node d[500001];
 8 bool cmp(node d1, node d2) {
 9     if(d1.x!=d2.x)
10     return d1.x < d2.x;
11     else     return d1.y < d2.y;
12 }
13 int main() {
14     ios::sync_with_stdio(false);
15     long long x, y, r, n;
16     cin >> x >> y >> r >> n;
17     long long sum = 0, ans = 0,bb,cc,error=0;
18     for (int i = 0; i < n;i++) {
19         cin >> b[i] >> c[i];
20         bb = b[i] - x;
21         cc = c[i] - y;
22         if (bb*bb+cc*cc <= r * r) {
23             if (bb == 0) {
24                 d[ans].x = 0;
25                 if(y<0)    d[ans].y = -77777777;
26                 else d[ans].y = 77777777;
27             }
28             else if (bb > 0) {
29             d[ans].x = 1.0; 
30             d[ans].y = cc * 1.0 / bb;
31             }
32             else {
33                 d[ans].x = -1.0;
34                 d[ans].y = cc * 1.0 / -bb;
35             }
36             ans++;
37         }
38     }
39     sort(d, d + ans, cmp);
40     if (ans != 0)sum++;
41     for (int i = 1; i < ans; i++)
42         if (d[i].y != d[i - 1].y)sum++;
43     cout << sum << endl;
44     return 0;
45 }

I - Jumpity Digits    Gym - 102279J

题目大意:给一个数字(最多100位),换两位,求比它小的最大数字。

思路:难题不会,水题做法贼多。最简单就是倒着扫一遍,找到第一个递增的数位,和后面比它小的最大的换一下,当然换首位要保证不能换成0。

代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 int main() {
 4     ios::sync_with_stdio(false);
 5     string s;
 6     int n,flag=0,r,l;
 7     cin >> s;
 8     n = s.length();
 9     char p;
10     for (int i = n-2; i >0; i--) {
11         int min = -1;
12         for (int j = n - 1; j > i; j--) {
13             if (s[j] - '0' < s[i] - '0' && s[j] - '0' >= min) {
14                 min = s[j] - '0';
15                 r = j;
16             }
17         }
18         if (min != -1) {
19             p = s[i];
20             s[i] = s[r];
21             s[r] = p;
22             flag = 1;
23             break;
24         }
25     }
26     if (flag == 0) {
27         int min = -1;
28         for (int j = n - 1; j > 0; j--) {
29             if (s[j] - '0' < s[0] - '0' && s[j] - '0' >= min && s[j] - '0' != 0) {
30                 min = s[j] - '0';
31                 r = j;
32             }
33         }
34         if (min != -1) {
35             p = s[0];
36             s[0] = s[r];
37             s[r] = p;
38             flag = 1;
39         }
40     }
41     if (flag == 0)cout << -1 << endl;
42     else cout << s << endl;
43     return 0;
44 }

训练赛14

A - Is It Easy ?   Gym - 102263A

虽然我是蒟蒻我也不会给一个a*b写题解吧?

B - Road to Arabella   Gym - 102263B

题目大意:小A声明一个正整数n,小K声明一个正整数k(1<=k<=n),两人轮流从n减去x,设当前的n为m,则1<=x<=max(1,m-k),谁拿到最后的数谁赢,现在给出n和k,问小K先手,谁赢?

思路:博弈论。分类讨论一下,怎样小K是必输的?n是偶数,但x只能等于1,必输。否则的话,小K先手拿第一次,一定可以掌控剩下数目,使得接下来每人只能拿1并且剩下的一定是奇数。小K便必赢。

代码(当时写的有点多余):

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int main() {
 4     std::ios::sync_with_stdio(false);
 5     int t;
 6     cin >> t;
 7     while (t--) {
 8         int n, k;
 9         cin >> n >> k;
10         if (k == 1) {
11             if (n == 2)cout << "Ayoub" << endl;
12             else cout << "Kilani" << endl;
13         }
14         else {
15             if (n - k <= 1) {
16                 if(n%2==0)cout << "Ayoub" << endl;
17                 else cout << "Kilani" << endl;
18             }
19             else {
20                 cout << "Kilani" << endl;
21             }
22         }
23     }
24     return 0;
25 }

E - Card Game    Gym - 102263G 

题目大意:n张牌上有1到n数字,小Z和小E各拿一张比点数,点数高的得到自己牌点数的分数,求小E在所有可能情况下得到分数的期望。

思路:数学期望等于发生概率乘结果的和。

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int main() {
 4     std::ios::sync_with_stdio(false);
 5     double n, sum = 0.0;
 6     cin >> n;
 7     for (double i = 2.0; i <= n+0.1; i=i+1.0) {
 8         sum += (i - 1) * i/n;
 9     }
10     printf("%.10f\n", sum);
11     return 0;
12 }

F - Steaks    Gym - 102263H 

题目大意:n张牛排k个锅,每张牛排有两面,每面要加热5分钟,每个锅能同时加热2张牛排。问全部加热完要几分钟。

思路:每个锅同时加热2张,看成一共有2k个锅就行了。分步走,第一步,将所有牛排都加热一遍,这里要分类讨论,如果牛排张数少于2k,那么剩余的空闲锅就不能运作。否则需要算出最后一轮加热第一面牛排还剩几个锅,让它们用来加热目前没在锅上的牛排的第二面。第二步,加热第二面就行了。

代码(这里更简单了,把每张牛排看成2张,排除一轮就能热完第一面的情况就好):

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int main() {
 4     std::ios::sync_with_stdio(false);
 5     long long n, k;
 6     cin >> n >> k;
 7     if (n / k < 2)cout << "10" << endl;
 8     else {
 9         if (n * 2 % (k * 2) == 0)cout << 5 * (n / k ) << endl;
10         else cout << 5 * (n / k + 1 ) << endl;
11     }
12     return 0;
13 }

H - Thanos Power      Gym - 102263J 

题目大意:灭霸种花。一次可以种或移除10的x次方朵花,问种N朵花至少要几步。

思路:一开始想用贪心,结果发现贪心要不就是改变了之前的状态,要不就是贪的不够。所以只能用DP。

          定义状态:dp[i][0]为到i位不进位最小花费,dp[i][1]为到i位向上进一位后再退位的最小花费。

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int dp[100010][2];
 4 int main() {
 5     std::ios::sync_with_stdio(false);
 6     string s;
 7     cin >> s;
 8     int n = s.length();
 9     dp[n - 1][0] = s[n - 1] - '0';
10     dp[n - 1][1] = 10 - (s[n - 1] - '0');
11     for (int i = n - 2; i >= 0; i--) {
12         dp[i][0] = min(dp[i + 1][0], dp[i + 1][1]+1) + s[i] - '0';
13         dp[i][1] = min(dp[i + 1][0], dp[i + 1][1]-1) + 10-(s[i] - '0');
14     }
15     cout << min(dp[0][0], dp[0][1]+1) << endl;
16     return 0;
17 }

I - Two Operations     Gym - 102263M 

题目大意:给一个小写字母字符串,两种操作:1.交换两个字母2.可以把两个相邻的相同字母变成下一个字母(当然z除外),问可得到结果的最大字典序。

思路:记录每种字母数量,从头到尾变一遍,别忘了变完后要给下一个加上去。然后从后往前输出字母即可。

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int main() {
 4     std::ios::sync_with_stdio(false);
 5     int a[30];
 6     string s;
 7     cin >> s;
 8     memset(a, 0, sizeof(a));
 9     for (int i = 0; i < s.length(); i++) {
10         a[s[i] - 'a']++;
11     }
12     for (int i = 0; i < 25; i++) {
13         if (a[i] / 2 > 0) {
14             a[i + 1] += (a[i] / 2);
15             a[i] =a[i]%2;
16         }
17     }
18     for (int i = 25; i >= 0; i--) {
19         for (int j = 0; j < a[i]; j++)
20             cout << (char)(i + 'a');
21     }
22     cout << endl;
23     return 0;
24 }

猜你喜欢

转载自www.cnblogs.com/Sympa/p/12951453.html
今日推荐