2023-01-25 13:24阅读: 80评论: 0推荐: 1

AtCoder Beginner Contest 172

A - Calc (abc172 a)

题目大意

给定一个a,输出 a+a2+a3

解题思路

模拟即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int a;
cin >> a;
cout << a + a * a + a * a * a << '\n';
return 0;
}


B - Minor Change (abc172 b)

题目大意

给定两个字符串st,问同位置下不同字符的位置数。

解题思路

模拟即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
string s, t;
cin >> s >> t;
int ans = 0;
for(int i = 0; i < s.size(); ++ i)
ans += (s[i] != t[i]);
cout << ans << '\n';
return 0;
}


C - Tsundoku (abc172 c)

题目大意

给定两个数组A,B和一个数s,从 A中取 x个数,从 B中取 y个数,要求这 x+y个数的和不超过s,且 x+y最大。

解题思路

给两个数组从小到大排个序,然后枚举x,二分找到最大的y,取最大的 x+y即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n, m;
LL k;
cin >> n >> m >> k;
vector<LL> a(n), b(m);
for(auto &i : a)
cin >> i;
for(auto &i : b)
cin >> i;
partial_sum(a.begin(), a.end(), a.begin());
partial_sum(b.begin(), b.end(), b.begin());
int ans = upper_bound(b.begin(), b.end(), k) - b.begin();
for(int i = 0; i < n; ++ i){
if (a[i] > k)
break;
ans = max(ans, i + 1 + int(upper_bound(b.begin(), b.end(), k - a[i]) - b.begin()));
}
cout << ans << '\n';
return 0;
}


D - Sum of Divisors (abc172 d)

题目大意

定义f(x)x的正因数的个数。

给定 n,求 k=1nk×f(k)

解题思路

问题求一个数,所有因数的个数,乘以该数,求和。

转换下求和,考虑因数贡献,即对于一个因数x,对于所有其倍数 y,都会对答案贡献 y

因此枚举因数,再枚举其倍数,求其倍数和即可。

时间复杂度为O(nlogn)

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n;
cin >> n;
LL ans = 0;
for(int i = 1; i <= n; ++ i){
for(int j = i; j <= n; j += i)
ans += j;
}
cout << ans << '\n';
return 0;
}


E - NEQ (abc172 e)

题目大意

要求统计俩数组对(A,B)的数量,满足长度均为nA,B数组中出现的数都在[1,m] 之间,且俩俩互不相同,且对于下标i ,要求AiBi

解题思路

对于数组A,有 Amn种取法,然后考虑数组 B有多少种取法。

因为数组A的所有取法都可以视为等价的,因此考虑数组 B时,可以认为数组 A1,2,..,n

此时相当于一个类错排问题,即从 [1,m]中取 n个数出来,要求第 i个位置上不能是数字 i

对于原错排问题,即从 [1,i]中取 i 个数出来,要求第 j个位置上不能是数字 j。其答案dpi=(i1)(dpi1+dpi2 。分别为

  • 考虑原[1,i1]子问题中的排列,将第 i个数, 放在第i位,然后再选择前面的 i1中的一个位置交换,得到一个新排列。
  • 考虑原[1,i2]子问题中的排列,第i个数放在第i位,第i1个数放在第i1位,然后交换这两个数,得到一个新排列。显然这第i1个数不一定是第 i1个数,它可以是前面任意一个。

在该问题多了mn个数,它不受任意条件限制。我们同样考虑递推求dpi的值。

  • 如果第 i个位置放 i,那么和上面的计算方式一样。

  • 如果第 i个位置放不受限制的数,有 mn个数可以选,放了之后,第 i个数也变成不受限制的数了,此时之后的状态,不受限制的数还是 mn个。

因此dpi=(mn)dpi1+(i1)(dpi1+dpi2)

答案就是Amndpn

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int mo = 1e9 + 7;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n, m;
cin >> n >> m;
vector<int> dp(n + 1);
dp[0] = 1;
dp[1] = m - n;
for(int i = 2; i <= n; ++ i){
dp[i] = (1ll * (m - n) * dp[i - 1] % mo + 1ll * (i - 1) * (dp[i - 1] + dp[i - 2]) % mo) % mo;
}
int ans = dp[n];
for(int i = m - n + 1; i <= m; ++ i){
ans = 1ll * ans * i % mo;
}
cout << ans << '\n';
return 0;
}


F - Unfair Nim (abc172 f)

题目大意

给定n堆石子,俩人玩 Nim游戏,即每次可从一堆石子取走至少一个石子,不能操作者输。

现在可以从第1堆拿一些石子放到第2堆(可以不拿,但不能拿空), 问拿走石子数的最小值,使得后手必胜。或告知不可行。

解题思路

根据sg理论,全部石子数异或和为 0则后手必胜。假设前两堆石子数和为x, 后面的石子数异或和为 y ,则题意转换为

ab,使得 a+b=x,ab=y ,且a不能超过第一堆石子数。最大化a

神奇的是 a+b=(ab)+2(a&b) ,即加法分为了不进位的加法进位两部分。

这样原问题进一步变为a&b=z,ab=y,其中 z=xy2

注意如果xy是小于 0或是 奇数则无解。

此时两个运算都是位运算,我们可以逐位考虑。对于zy的某一位的情况:

  • 如果是 1,1,则 无解,无法做到x&y=1,xy=1
  • 如果是 1,0,则 a,b在该位都必须为1
  • 如果是 0,1,则 a,b仅有一个在该位为 1
  • 如果是 0,0,则 a,b在该位都必须为 0

因此我们可以构造出不大于第一堆石子数的最大的a

第一种情况相当于z&y0,此时无解。

由于1,0的情况两者都必须为1,因此我们可以初始化 a的值为 z,然后从高位依次判断y的每一位,看看让a在该位为 1会不会大于第一石子数,不大于则可以为1

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n;
cin >> n;
vector<LL> a(n);
for(auto &i : a){
cin >> i;
}
LL x = a[0] + a[1];
LL y = 0;
for(int i = 2; i < n; ++ i)
y = y ^ a[i];
auto solve = [&](){
if ((x - y < 0) || ((x - y) & 1))
return a[0] + 1;
x = (x - y) / 2;
if ((x & y) != 0)
return a[0] + 1;
if (x > a[0])
return a[0] + 1;
LL ans = x;
for(int i = 60; i >= 0; -- i){
if (((y >> i) & 1) && ans + (1ll << i) <= a[0])
ans += (1ll << i);
}
if (ans == 0)
ans = a[0] + 1;
return ans;
};
LL ans = solve();
cout << a[0] - ans << '\n';
return 0;
}


本文作者:~Lanly~

本文链接:https://www.cnblogs.com/Lanly/p/17066875.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   ~Lanly~  阅读(80)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.