ATcoderAtCoder Beginner Contest 161 题解
Posted zcr-blog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ATcoderAtCoder Beginner Contest 161 题解相关的知识,希望对你有一定的参考价值。
题目链接: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 }
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 }
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 }
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 }
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} imes 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 }
以上是关于ATcoderAtCoder Beginner Contest 161 题解的主要内容,如果未能解决你的问题,请参考以下文章
AtCoderAtCoder Grand Contest 041 解题报告(开坑之时已至,目前只有$A,B,C$)
AtCoderAtCoder Grand Contest 041 解题报告(开坑之时已至,目前只有$A,B,C$)
AtCoderAtCoder Grand Contest 040 解题报告
ruby Códigodelnivel 8,modo Beginner de RubyWarrior