码迷,mamicode.com
首页 > 其他好文 > 详细

【ATcoder】AtCoder Beginner Contest 161 题解

时间:2020-04-04 22:54:54      阅读:100      评论:0      收藏:0      [点我收藏+]

标签:img   问题   ==   ber   for   event   列排序   初始化   bst   

题目链接:AtCoder Beginner Contest 161

原版题解链接:传送门

A - ABC Swap

这题太水,直接模拟即可。

技术图片
 1 #include <iostream>
 2 using namespace std;
 3 int main() {
 4     int a, b, c;
 5     cin >> a >> b >> c;
 6     swap(a, b);
 7     swap(a, c);
 8     cout << a << " " << b << " " << c << endl;
 9     return 0;
10 }
STL版
技术图片
 1 #include <iostream>
 2 using namespace std;
 3 int main() {
 4     int a, b, c, tmp;
 5     cin >> a >> b >> c;
 6     tmp = a;
 7     a = b;
 8     b = tmp;
 9     tmp = a;
10     a = c;
11     c = tmp;
12     cout << a << " " << b << " " << c << endl;
13     return 0;
14 }
手写版

B - Popular Vote

这题也很水!(这次ABC都挺水)

求出那个题目要求的值,然后对序列排序,从大到小枚举看有多少个不小于,最后与 $m$ 比较即可。

此题需要double,其实向上取整也可以。

技术图片
 1 #include <iostream>
 2 #include <algorithm>
 3 using namespace std;
 4 int n, m, a[1000], sum;
 5 int main() {
 6     cin >> n >> m;
 7     for (int i = 1; i <= n; i++) {
 8         cin >> a[i];
 9         sum += a[i];
10     }
11     sum = (sum + 4 * m - 1) / (4 * m);//向上取整
12     sort(a + 1, a + n + 1);
13     for (int i = n; i >= 1; i--) {
14         if (a[i] >= sum) {
15             m--;
16         } else {
17             break;
18         }
19     }
20     if (m > 0) puts("No");
21     else puts("Yes");
22     return 0;
23 }
B

C - Replacing Integer

我们对问题进行分类讨论。

(1)若 $n \leq k$,则只会出现两种情况:$n 或 k-n$(因为 $k-(k-n)=n$,有循环回来了),输出较小值即可。

(2)否则,$n$ 会一直减 $k$,一直减到 $n < k$时,这个过程最终得到的其实就是 $n模k$,然后就到了(1)。

技术图片
 1 #include <iostream>
 2 #include <algorithm>
 3 #include <map>
 4 #include <cmath>
 5 using namespace std;
 6 typedef long long ll;
 7 ll n, k;
 8 ll F(ll n, ll k) {
 9     if (n <= k) {
10         return min(n, k - n);
11     }
12     return F(n % k, k);
13 }
14 int main() {
15     cin >> n >> k;
16     cout << F(n, k);
17     return 0;
18 }
C

D - Lunlun Number

此题本人是用 $dp+构造$ 做的。

设 $dp[i][j]$ 代表以 $i$ 开头,有 $j$ 位的lunlun数有多少个。

根据样例的提示,其实 $j$ 最大也就 $10$。$i$ 在 $[0,9]$。

首先初始化所有 $dp[i][1]=1$。

然后不难想到转移方程 $dp[i][j]=dp[i-1][j-1]+dp[i][j-1]+dp[i+1][j-1]$。

当然如果 $i=0或i=9$ 时要特殊处理(具体见代码)。

接下来开始构造。

首先算出第 $k$ 个数的位数。

这很好办,我们只用统计每个位数有多少lunlun数,然后做一遍前缀和,从小到大遍历,找到第一个大于等于 $k$ 的位数即为 $k$ 的位数。

确定好位数之后我们就可以开始枚举每一位是什么了。

当然不是暴力枚举。

如果是第一位,我们暴力枚举 $1-9$,用找位数同样的方法,我们可一个确定第一个位置的数(我们记录了以 $i$ 开头,有 $j$ 位的lunlun数有多少个)。

然后后面的位置的数只有最多三种选择——上次减一,上次同样和上次加一(记住不能小于 $0$ 或大于 $9$)。

然后再用相同的方法即可。

技术图片
 1 #include <iostream>
 2 #include <algorithm>
 3 #include <map>
 4 #include <cmath>
 5 using namespace std;
 6 typedef long long ll;
 7 ll dp[10][20];//dp[i][j]代表以i开头的j位数有多少个lunlun 
 8 ll sum[20], pos;
 9 ll k;
10 void dfs(ll num, ll lst) {
11     if (num > pos) return;
12     if (num == 1) {
13         for (ll i = 1; i < 10; i++) {
14             if (k > dp[i][pos - num + 1]) {
15                 k -= dp[i][pos - num + 1];
16             } else {
17                 cout << i;
18                 dfs(num + 1, i);
19                 break;
20             }
21         }
22     } else {
23         for (ll i = lst - 1; i <= lst + 1; i++) {
24             if (i < 0 || i > 9) continue;//记住特判 
25             if (k > dp[i][pos - num + 1]) {
26                 k -= dp[i][pos - num + 1];
27             } else {
28                 cout << i;
29                 dfs(num + 1, i);
30                 break;
31             }
32         }
33     }
34 }
35 int main() {
36     cin >> k;
37     for (ll i = 0; i < 10; i++) {
38         dp[i][1] = 1;
39     }
40     sum[1] = 9;
41     for (ll j = 2; j <= 10; j++) {
42         for (ll i = 0; i < 10; i++) {
43             if (i != 0 && i != 9) dp[i][j] = dp[i - 1][j - 1] + dp[i][j - 1] + dp[i + 1][j - 1];
44             else if (i != 0) dp[i][j] = dp[i - 1][j - 1] + dp[i][j - 1];
45             else if (i != 9) dp[i][j] = dp[i][j - 1] + dp[i + 1][j - 1];
46             if (i != 0) sum[j] += dp[i][j];
47         }
48     }
49     for (ll i = 1; i <= 20; i++) {
50         if (k > sum[i]) {
51             k -= sum[i];
52         } else {
53             pos = i;
54             break;
55         }
56     }
57     dfs(1, 0);
58     return 0;
59 }
D

E - Yutori

待填坑

F - Division or Substraction

我觉得这题应该和E换换位置。

首先这题有两种情况:

1 不是 $n$ 的约数

这种情况比较简单,不是 $n$ 的约数根据题意 $n$ 会一直减 $k$,减到 $n<k$。

最后得到的其实就是 $n模k$(好像和C有点像)。

我们需要找的其实就是所有 $k$ 使得 $n模k=1$。

这其实就是 $n-1$ 的约数,所以直接查询 $n-1$ 的约数(不包括1)个数即可。时间复杂度:$O(\sqrt{n})$

2 是 $n$ 的约数

这种情况其实更好想。

我们首先要找到所有约数(不包括1),这样做的复杂度是$O(\sqrt{n})$

根据题目要求我们要不断的除以这个约数,而因为 $k \geq 2$ 所以这是$O(\log{n})$ 的。

而当它不整除时,就变成了1,得到的会是 $n模k$(此时的 $n$ 应是除以 $k$ 若干遍后的 $n$),如果 $n模k==1$ 则 $ans++$。

总复杂度 $O(\sqrt{n} \times \log{\sqrt{n}})$。

记得 $n$ 一定是一个满足条件的 $k$。

记住要特判“2”。

技术图片
 1 #include <iostream>
 2 #include <algorithm>
 3 #include <map>
 4 #include <cmath>
 5 using namespace std;
 6 typedef long long ll;
 7 ll n;
 8 ll F(ll x) {
 9     ll ret = 1;
10     for (ll i = 2; i * i <= x; i++) {
11         if (x % i == 0) {
12             ret += 2;
13             if (x / i == i) ret--;
14         }
15     }
16     return ret;
17 }
18 ll G(ll x) {
19     ll ret = 1, tp;
20     for (ll i = 2; i * i <= x; i++) {
21         if (x % i == 0) {
22             ll tmp = x / i;
23             tp = x;
24             while (tp % i == 0) {
25                 tp /= i;
26             }
27             if (tp > i) tp %= i;
28             ret += (tp == 1);
29             if (tmp != i) {
30                 tp = x;
31                 while (tp % tmp == 0) {
32                     tp /= tmp;
33                 }
34                 if (tp > tmp) tp %= tmp;
35                 ret += (tp == 1);
36             }
37         }
38     }
39     return ret;
40 }
41 int main() {
42     cin >> n;
43     if (n == 2) {
44         cout << 1;
45         return 0;
46     }
47     cout << F(n - 1) + G(n);
48     return 0;
49 }
F

【ATcoder】AtCoder Beginner Contest 161 题解

标签:img   问题   ==   ber   for   event   列排序   初始化   bst   

原文地址:https://www.cnblogs.com/zcr-blog/p/12634639.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!