补题链接:Here
1538A. Stone Game
数组 的大小为
,请问每次可以删除最左和最右侧的元素,请问最少执行多少次能删除掉数组中的最大值和最小值 (
)
在输入的时候确定最大值和最小值的下标,
4种情况
比较从左边删除和右边删除的情况即可
void solve() {int n; cin >> n;int id1, id2;for (int i = 1, x; i <= n; ++i) {cin >> x;if (x == 1)id1 = i;if (x == n)id2 = i;}if (id1 > id2) swap(id1, id2);int cnt1 = (id1 + min(n - id2 + 1, id2 - id1));int cnt2 = (n - id2 + 1 + min(id1, id2 - id1));cout << min(cnt1, cnt2) << "\n";}
void solve() {int n; cin >> n;vector<int>a(n);for (int &x : a)cin >> x;int maxPos = max_element(a.begin(), a.end()) - a.begin();int minPos = min_element(a.begin(), a.end()) - a.begin();cout << min({max(maxPos, minPos) + 1,(n - 1) - min(maxPos, minPos) + 1,(n - 1) - maxPos + minPos + 2,(n - 1) - minPos + maxPos + 2}) << "\n";}
1538B. Friends and Candies
Polycarp 要对他的 个朋友的蛋糕数量重新分配,使得每个人的蛋糕数量相同。
找到最小的
进行分配
数学题,
首先如果总的蛋糕数不是 的倍数,直接输出
,接下来在统计大于平均值的人数即可
void solve() {int n; cin >> n;ll cnt = 0;vector<int>a(n);for (int &x : a)cin >> x, cnt += x;if (cnt % n != 0) {cout << -1 << "\n"; return ;}int c = 0;cnt /= n;for (int i = 0; i < n; ++i) {if (a[i] > cnt)c++;}cout << c << "\n";}
1538C. Number of Pairs
在数组 中寻找最大对数的
%20(1%5Cle%20i%20%3C%20j%20%5Cle%20n)#card=math&code=%28i%2Cj%29%20%281%5Cle%20i%20%3C%20j%20%5Cle%20n%29&id=GIM71) 使得
简单来说要统计两种情况
二分上面两种情况,然后相减就是合适的区间长度了。
但要注意如果本身 就符合情况的话会重复计算一次,要减去一
最后输出
双指针写法
void solve() {int n; ll L, R;cin >> n >> L >> R;vector<ll>a(n + 1);for (int i = 1; i <= n; ++i)cin >> a[i];sort(a.begin() + 1, a.end());int l = 2, r = n;ll cnt = 0;while (l <= n and a[1] + a[1] <= L)l++;for (int i = 1; i <= n; ++i) {while (l > 1 and a[l - 1] + a[i] >= L)l--;while (r > i and a[r] + a[i] > R)r--;if (r >= max(l, i)) {if (l > i)cnt += (r - l + 1);else cnt += r - i;}}cout << cnt << '\n';}
二分写法
void solve() {int n, l, r ;cin >> n >> l >> r;vector<int>a(n);for (int &x : a)cin >> x;sort(a.begin(), a.end());ll ans = 0;for (int i = 0; i < n; ++i) {ans += upper_bound(a.begin(), a.end(), r - a[i]) - a.begin();ans -= lower_bound(a.begin(), a.end(), l - a[i]) - a.begin();if (2 * a[i] >= l && a[i] * 2 <= r)ans--;}cout << ans / 2 << "\n";}
1538D. Another Problem About Dividing Numbers
给与 和
两个整数,在一回合操作里,
和
两个整数都要找出
请问是否能在 个回合结束后使得
看样例想到是质因数个数的问题,
但试了下先欧拉素数筛晒出 的数据还是 TLE了(常数太大了),然后尝试直接统计因子个数,注意使用
scanf 而不是 cin)
void solve() {int a, b, k;scanf("%d%d%d", &a, &b, &k);if (k == 1) {puts(a != b && (a % b == 0 || b % a == 0) ? "YES" : "NO");return ;}int cnt = 0;for (int i = 2; i * i <= b; ++i) {while (b % i == 0) {b /= i; cnt++;}}if (b != 1)cnt++;for (int i = 2; i * i <= a; ++i) {while (a % i == 0) {a /= i;cnt++;}}if (a != 1)cnt++;puts(cnt >= k ? "YES" : "NO");}
1538E. Funny Substrings
没看懂题意,以后补
1538F. Interesting Function
這道題比賽沒寫出來虧了一個億
给定两个整数 和
,其中
。 我们将向
加 1,直到结果等于
。 因此,将执行
次加法。 对于每个这样的加法,让我们看看在它之后将更改的位数。
累加不同位数的情况下 ,直到
和
void solve() {ll l, r;cin >> l >> r;ll ans = 0;while (l != 0 || r != 0) {ans += (r - l);l /= 10, r /= 10;}cout << ans << "\n";}
如果这算数位DP, 那么算是我见过最简单的数位DP了.
ll dp[20];void init(int n) {dp[1] = 1;for (int i = 2; i <= n; ++i)dp[i] = dp[i - 1] * 10 + 1;}int cnt(ll x) {int a[20] = {0}, Cnt = 0;while (x) {a[Cnt++] = x % 10;x /= 10;}ll ans = 0;for (int i = Cnt - 1; i >= 0; --i)ans += dp[i + 1] * a[i];return ans;}void solve() {ll l, r;cin >> l >> r;cout << cnt(r) - cnt(l) << "\n";}int main() {ios::sync_with_stdio(false), cin.tie(nullptr);init(15);int _; for (cin >> _; _--;) solve();return 0;}
1538G. Gift Set
Polycarp 有 x 个红色糖果和 y 个蓝色糖果。 使用它们,他想制作礼品套装。 每个礼品套装包含一个红色糖果和 b 个蓝色糖果,或一个蓝色糖果和 b 个红色糖果。 任何糖果最多只能属于一个礼品套装。
帮助 Polycarp 找到他可以创造的最大数量的礼品套装。
例如,如果 ,那么 Polycarp 可以制作三套礼物:
- 第一套有 5 个红色糖果和 2 个蓝色糖果;
- 第二组将有 5 个蓝色糖果和 2 个红色糖果;
- 第三组将有 5 个蓝色糖果和 2 个红色糖果。
思路来自 Arctic_Clam
考虑二分可分的集合的数量。
如何 #card=math&code=O%281%29&id=Qa68x) 求给定的某个集合可行与否?
不妨设
记 为要验证的集合数量,
为第 一种集合数量,
为 第二种集合数量。
于是我们有
变形可以得到
也就是说,给定n,我们可以求出s的取值区间。再判定下该区间是否合法即可。
取值区间的左界应该是向下取整,但是
和
都是负数,而
C++默认是趋零取整,所以要特判。
ll x, y, a, b;bool check(ll n) {ll l = (x - n * b) / (a - b);if ((x - n * b) < 0 and (-(x - n * b)) % (b - a) != 0)l++;ll r = (y - n * a) / (b - a);return l <= r and r >= 0 and l <= n;}void solve() {cin >> x >> y >> a >> b;if (x > y) swap(x, y);if (a > b) swap(a, b);if (a == b) {cout << (x /= a) << "\n";return ;}ll l = 0, r = x;while (l < r) {if (l == r - 1) {if (check(r)) l = r;break;}ll mid = (l + r) >> 1;if (check(mid)) l = mid;else r = mid - 1;}cout << l << '\n';}
似乎本题也可以三分做,dalao也对三分做了正确性证明(tql
二分的正确性是显然的,但是三分的正确性并不那么显然。
为了证明三分的正确性,我们需要证明集合总数n是第一集合数s的函数,且该函数至多有一个峰。
下面给出证明:

