A 取因数

题目大意

在纸上写一个数字 n,双方每次选择 n 的一个因数,然后划掉 n 并在纸上写下 n 减去这个数字的差使之成为新的 n,最后写数字 0 的人输。Alice先手。

主要思路

  • 奇数的因数都是奇数,因此奇数一定会变成偶数
  • 偶数可以通过-1变成奇数
  • 那么如果先手是偶数,那么可以通过-1维持对手是奇数,自己一直是偶数,持续到自己为2时,对手为1,对手必输,先手必胜

结论:偶数先手必胜,奇数先手必输

AC代码

  1. #include <iostream>
  2. #include <cstring>
  3. #include <string>
  4. #include <algorithm>
  5. #include <stack>
  6. #include <string>
  7. #include <cmath>
  8. #include <unordered_map>
  9. #include <queue>
  10. #include <map>
  11. using namespace std;
  12. #define int long long
  13. #define debug(a) cout << #a << " = " << a << endl;
  14. #define x first
  15. #define y second
  16. typedef pair<int, int> P;
  17. const int N = 200010;
  18. int n, a[N];
  19. signed main(void)
  20. {
  21. cin >> n;
  22. if(n % 2) puts("Bob");
  23. else puts("Alice");
  24. return 0;
  25. }

B A + B

题目大意

中文题

主要思路

n最大是100,因为k只有2,所以分3种情况即可

  • k == 0,可以从1020往后枚举n个
  • k == 1,可以枚举a = 10, b = 1, c = 11, 每轮b++, c++
  • k == 2,枚举a = 1, b = 11, c = 12,每轮a++, b为两个a合并(比如a = 1,b变为11,a为2,b变为22),c = a + b,也就是a + aa == aa + a形式

AC代码

  1. #include <iostream>
  2. #include <cstring>
  3. #include <string>
  4. #include <algorithm>
  5. #include <stack>
  6. #include <string>
  7. #include <cmath>
  8. #include <unordered_map>
  9. #include <queue>
  10. #include <map>
  11. using namespace std;
  12. #define int long long
  13. #define debug(a) cout << #a << " = " << a << endl;
  14. #define x first
  15. #define y second
  16. typedef pair<int, int> P;
  17. const int N = 200010;
  18. int n, a[N];
  19. int f(int x)
  20. {
  21. int t = x;
  22. int cnt = 0;
  23. while(x)
  24. {
  25. x /= 10;
  26. cnt++;
  27. }
  28. return t * (int)pow(10, cnt) + t;
  29. }
  30. signed main(void)
  31. {
  32. int n, k;
  33. cin >> k >> n;
  34. if(k == 0)
  35. {
  36. int t = 1020;
  37. for(int i = 0; i < n; i++)
  38. {
  39. cout << t << endl;
  40. t++;
  41. }
  42. }
  43. else if(k == 1)
  44. {
  45. int a = 10, b = 1, c = 11;
  46. for(int i = 0; i < n; i++)
  47. {
  48. cout << a << b << c << endl;
  49. b++, c++;
  50. }
  51. }
  52. else
  53. {
  54. int a = 1, b = 11, c = 12;
  55. for(int i = 0; i < n; i++)
  56. {
  57. cout << a << b << c << endl;
  58. a++, b = f(a), c = a + b;
  59. }
  60. }
  61. return 0;
  62. }

C 取钱

题目大意

中文题

主要思路

我们先预处理出用a[i]纸币能凑不超过a[i + 1]金额的金额最大值sum和纸币张数cnt。

读入每一个金额b,先二分出小于等于b的a[i]的最大值,然后获得纸币数量最大值为cnt[i - 1] + (b - sum[i - 1]) / a[i], 金额为sum[i - 1] + (b - sum[i - 1]) / a[i] + a[i]

核心思想:贪心,从小到大将每一个a[i]的数量最大化

AC代码

  1. #include <iostream>
  2. #include <cstring>
  3. #include <string>
  4. #include <algorithm>
  5. #include <stack>
  6. #include <string>
  7. #include <cmath>
  8. #include <unordered_map>
  9. #include <queue>
  10. #include <map>
  11. using namespace std;
  12. #define int long long
  13. #define debug(a) cout << #a << " = " << a << endl;
  14. #define x first
  15. #define y second
  16. typedef pair<int, int> P;
  17. const int N = 200010;
  18. int n, a[N];
  19. int cnt[N];
  20. int sum[N];
  21. signed main(void)
  22. {
  23. cin >> n;
  24. for(int i = 1; i <= n; i++) cin >> a[i];
  25. a[n + 1] = 1e18+1;
  26. for(int i = 1; i <= n; i++)
  27. {
  28. int t = (a[i + 1] - sum[i - 1] - 1) / a[i];//t为最大金额小于a[i + 1],会用到最多多少a[i]
  29. cnt[i] = cnt[i - 1] + t;//总纸币数量
  30. sum[i] = sum[i - 1] + a[i] * t;//总价
  31. }
  32. int T;
  33. cin >> T;
  34. while(T--)
  35. {
  36. int num;
  37. cin >> num;
  38. int l = 0, r = n + 1;
  39. while(l < r)//二分小于等于当前num的最大面额
  40. {
  41. int mid = l + r + 1 >> 1;
  42. if(a[mid] <= num) l = mid;
  43. else r = mid - 1;
  44. }
  45. cout << sum[l - 1] + (num - sum[l - 1]) / a[l] * a[l] << ' ' << cnt[l - 1] + (num - sum[l - 1]) / a[l] << endl;
  46. }
  47. return 0;
  48. }