抱歉B、C题咕了这么久

B. Minimum Product #枚举 #贪心

题目链接

题意

给定四个整数\(a, b, x, y\),其中\(a\geq x, b\geq y\),你可以执行不超过\(n\)次的操作:选择\(a\)或者\(b\),减一。操作保证\(a\)不会低于\(x\),\(b\)不会低于\(y\)。现要你求出\(a\)与\(b\)的最小乘积

分析

容易知道结论,要使乘积变小,一定是要将尽可能多的减少量放到某一个数,而不是将减少量均摊给两个数。[*不完全证明见后]

由此,最终结果无非是两种情况,1) 要么先对\(a\)做减法,只有当新\(a\)不能再做减法时,再对\(b\)做减法。2) 要么先对\(b\)做减法,只有当新\(b\)不能再做减法时,再对\(a\)做减法。于是我们对这两种情况得到的乘积进行比较,就能得到最小乘积了。

[不完全证明]:翻译自@pritishn思路,假设两个数字\(a,b\),你可以将他们进行总共两次减法操作。无疑有三种选择:(i) \(a-1, b-1\) ,得到的乘积为\(ab-a-b+1\);(ii)\(a-2, b\),得到乘积为\(ab-2b\);(iii)\(a, b-2\),得到乘积为\(ab-2a\)。

不妨设\(b>a\),显然\(ab-a-b+1>ab-a-b>(因为b>a)ab-2b\),显然情况(i)的乘积比情况(ii)大,同理也可以证明情况(ii)乘积比情况(iii)大。

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 5;
const int MOD = 1e4 + 7;
int q;
int main(){
scanf("%d", &q);
while(q--){
ll a, b, x, y, n;
scanf("%lld%lld%lld%lld%lld", &a, &b, &x, &y, &n);
ll cura = max(a - n, x); //得到a的下限
ll len = n - (a - cura);
ll curb = max(b - len, y); //b的下限
ll ans1 = cura * curb; curb = max(b - n, y);
len = n - (b - curb);
cura = max(a - len, x);
ll ans2 = cura * curb;
printf("%lld\n", min(ans1, ans2));
}
return 0;
}

C. Yet Another Array Restoration #数学 #暴力 #构造

题目链接

题意

你需要构造一个数组,其中它有\(n\)个不同正整数,同时它必须包含\(x, y\)两个已知正整数(\(x<y\)),这个数组(\(a_1<a_2<...<a_n\))经过升序排序后所有相邻元素必须差值相等,即\(a_2-a_1=a_3-a_2=...=a_n-a_{n-1}\)。现要你找到这样的数组并输出,同时该数组中的最大元素越小越好。

分析

题目要求构造的数组,显然是等差数列。因此我们核心思想就是确定首项及公差后,判断\(x,y\)是否在该数列即可。

怎么确定公差?我们知道公差一定是\(y-x\)的约数,\(d_{max}=y-x\),我们就从\(d=1\)到\(d=d_{max}\)开始确定首项\(a_0\),为了保证数组最大值越小越好,一定是希望\(y\)越接近最大值越好(即y前面能够拓展足够多的元素)。于是我们从\(y\)开始递减,如果能够向前拓展到\(n\)个元素,说明当前的\(d\)是最优的。如果不行,我们就将\(a_0\)确定在尽可能小的正整数,然后以\(a_0, a_0+d, a_0+2d, ... , a_0+d*(n-1)\)拓展元素,于是题目中要求的数组就确定下来了。公差的从小到大递增,一旦发现合法,同时又因为其枚举次序符合最优性,便可直接输出。

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 5;
const int MOD = 1e4 + 7;
int q;
int main(){
scanf("%d", &q);
while(q--){
int n, x, y;
scanf("%d%d%d", &n, &x, &y);
int diff = y - x;
for(int d = 1; d <= diff; d++){
if(diff % d != 0) continue; //说明公差的整数倍并不是两值差值,x利用该公差无法到达y
if(diff / d + 1 > n) continue; //说明该公差下,x到达y所经过的元素太多了
int k = min((y - 1) / d, n - 1); //注意,(y-1)/d保证a0落在最接近于1的位置
int a0 = y - k * d;
for (int i = 0; i < n; i++){
printf("%d%c", a0 + i * d, (i == n - 1) ? '\n' : ' ');
}
break;
}
}
return 0;
}

D. Decrease the Sum of Digits #模拟 #暴力

题目链接

题意

给定正整数\(n\),每次操作可对\(n\)(\(\leq 10^{18}\))自增。你需要求出最少操作次数(同时也就是“增数”),使得将\(n\)增至某个数后所有数位数字之和,不大于\(s\)。

分析

观察到\(n\)的长度最多为18,我们可以自数字低位到最高位,尝试对每一位进行归零(实际上就是将该位的数字加到进十),并实时检查当前递增后的\(n\)的数字之和是否满足题意,时间复杂度为\(O(log^2_{10}(n))\),对于该数据范围十分稳妥。

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 5;
const int MOD = 1e4 + 7;
int q;
int sum[20];
int Cal(ll x){ //计算x所有数位之和
int res = 0;
while(x){
res += (x % 10);
x /= 10;
}
return res;
}
int main(){
scanf("%d", &q);
while(q--){
ll n, tmp; int s, tot = 0;
scanf("%lld%d", &n, &s);
if(Cal(n) <= s) {
printf("0\n"); continue;
}
ll mul = 1, ans = 0;
for (int i = 0; i < 19; i++){
int cur = (n / mul) % 10; //获得第i+1位数字
ll diff = (10 - cur) * mul; //进位所需的差值
n += diff; //包含进位
ans += diff;
if(Cal(n) <= s) break;
mul *= 10;
}
printf("%lld\n", ans);
}
return 0;
}

E. Two Platforms #二分 #枚举

题目链接

题意

(飞机和飞机场太不形象了)

有n个球,第\(i\)个球坐标为(\(x_i, y_i\)),他们正要掉下来,现在你只有两个长度为\(k\)的水平盘子(如果盘子左端点为\(x\),则右端点为\(x+k\),两端点也能装下球),需要你放置将这两个盘子放置到某个位置,将尽可能多的掉下来的球装下。求最多能装多少个球。

分析

感谢@issue敲腻害的思路。

题目中的\(y_i\)对答案没有影响,我们只考虑\(x_i\),因而首先将所有球\(x\)坐标升序排序。接着,我们先考虑拿一个盘子去接球,从右到左枚举所有球的坐标,通过二分算法计算出该盘子当前从左端点起,能接到的球数量。为什么从右到左遍历?因为我们需要后缀和数组ri实时维护在区间[\(x[i], x[n]\)]中,任何位置放下盘子,能接到球的最大数量

然后我们再拿另一盘子去接,此时从左到右枚举球的起点,并二分出能接到的数量。那么最后更新答案时,其实就是以\(i\)作为分界线, 第一个盘子装下左区间[\(x[i], x[i]+k\)] 的球数量,再加上第二个盘子在右区间(该右区间不一定连接于左区间)装下的球最大数量。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <stack>
#include <string>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
const int MAXN = 2e5+5;
int q, n, k;
int x[MAXN], y[MAXN], le[MAXN], ri[MAXN];
int main(){
scanf("%d", &q);
while(q--){
scanf("%d%d", &n, &k);
for(int i = 1; i <= n + 1; i++) ri[i] = 0;
for(int i = 1; i <= n; i++) scanf("%d", &x[i]);
for(int i = 1; i <= n; i++) scanf("%d", &y[i]);
sort(x + 1, x + n + 1);
for(int i = n; i >= 1; i--){
int xfar = x[i] + k; //从第i个球的位置开始装,盘子能够到达的右端点
int pos = upper_bound(x + 1, x + 1 + n, xfar) - x; //得到右端点对应索引
ri[i] = max(pos - i, ri[i + 1]); //实时更新盘子放在[i, n]区间中任意位置中,接下球的最大数量
}
int ans = -1;
for(int i = 1; i <= n; i++){ //从1开始枚举另一盘子的左端点
int xfar = x[i] + k; //该盘子的右端点
int pos = upper_bound(x + 1, x + 1 + n, xfar) - x;
ans = max(ans, pos - i + ri[pos]);
}
printf("%d\n", ans);
}
return 0;
}

Codeforces Round #667 (Div. 3) B、C、D、E 题解的更多相关文章

  1. Codeforces Round #524 (Div. 2)(前三题题解)

    这场比赛手速场+数学场,像我这样读题都读不大懂的蒟蒻表示呵呵呵. 第四题搞了半天,大概想出来了,但来不及(中途家里网炸了)查错,于是我交了两次丢了100分.幸亏这次没有掉rating. 比赛传送门:h ...

  2. Codeforces Round #667 (Div. 3)

    比赛链接:https://codeforces.com/contest/1409 A. Yet Another Two Integers Problem 题意 给出两个数 $a$ 和 $b$,有以下两 ...

  3. Codeforces Round #667 (Div. 3) E. Two Platforms (双指针)

    题意:有\(n\)个点往下落,你可以在最下面放两个长度为\(k\)的板子,问做多能接到多少个点. 题解:这题给纵坐标\(y\)完全没有用,我们先对横坐标\(x\)排序,然后从左边开始枚举,用\(l[i ...

  4. Codeforces Round #667 (Div. 3) D. Decrease the Sum of Digits (贪心)

    题意:给你一个正整数\(n\),每次可以对\(n\)加一,问最少操作多少次是的\(n\)的所有位数之和不大于\(s\). 题解:\(n\)的某个位置上的数进位,意味这后面的位置都可以被更新为\(0\) ...

  5. Codeforces Round #667 (Div. 3) C. Yet Another Array Restoration (数学)

    题意:给你两个数字\(x\)和\(y\),让你构造一个长度为\(n\)的序列,要求包含\(x\)和\(y\),并且排序后相邻两项的差值相等. 题解:有排序后相邻两项的差值相等可知,构造的序列排序后一定 ...

  6. Codeforces Round #667 (Div. 3) B. Minimum Product (贪心,数学)

    题意:给你\(a\)和\(b\)两个数,每次操作可以是任意一个数\(-1\),最多操作\(n\),并且\(a\ge x\),\(b\ge y\),求操作后\(a*b\)的最小值. 题解:观察样例并且在 ...

  7. Codeforces Round #796 (Div. 2)(A~E题题解)

    文章目录 原题链接: A.Cirno's Perfect Bitmasks Classroom 思路 代码 B.Patchouli's Magical Talisman 思路 代码 C.Manipul ...

  8. Codeforces Round #530 (Div. 2) (前三题题解)

    总评 今天是个上分的好日子,可惜12:30修仙场并没有打... A. Snowball(小模拟) 我上来还以为直接能O(1)算出来没想到还能小于等于0的时候变成0,那么只能小模拟了.从最高的地方进行高 ...

  9. Codeforces Round #646 (Div. 2)【B. Subsequence Hate题解】

    具体思路已经在代码注释中给出,这里不再赘述. #include<iostream> #include<algorithm> using namespace std; int t ...

随机推荐

  1. C2. Balanced Removals (Harder) (幾何、思維)

    Codeforce 1237C2 Balanced Removals (Harder) (幾何.思維) 今天我們來看看CF1237C2 題目連結 題目 給你偶數個三維座標點,每次選其中兩點,如果兩點為 ...

  2. 一站式Web开发套件BeetleX.WebFamily

    BeetleX.WebFamily是一款前后端分离的Web开发套件,但它并不依赖于nodejs/npm/webpack等相关工具:而使用自身实现的方式来完成前后端分离的Web应用开发:套件以组件的方式 ...

  3. 深度对比Apache CarbonData、Hudi和Open Delta三大开源数据湖方案

    摘要:今天我们就来解构数据湖的核心需求,同时深度对比Apache CarbonData.Hudi和Open Delta三大解决方案,帮助用户更好地针对自身场景来做数据湖方案选型. 背景 我们已经看到, ...

  4. excel--text()函数

  5. 【Luogu】P1402 酒店之王 题解

    原题链接 这道题,很明显是个配对问题.于是,我们可以想到用网络最大流来做. 先整理一下题目条件. 很明显,根据贪心思想,要使最多人满意,每个人应该最多睡一个房间(似乎也没有人能睡两个房间),吃一道菜. ...

  6. 简单Emacs配置

    (global-set-key [f9] 'compile-file) (global-set-key [f10] 'gud-gdb) (global-set-key (kbd "C-s&q ...

  7. Luogu P2024 [NOI2001]食物链

    并查集 首先先要读懂题目,a是b的食物的话,b的天敌是a,b的食物是a的天敌 比如,人吃鸡,鸡吃草,那么草吃人..... 所以建3个并查集,+n时表示这是其食物,+2*n时表示这是其天敌 所以当x,y ...

  8. 【Kata Daily 191012】Find numbers which are divisible by given number

    题目: Complete the function which takes two arguments and returns all numbers which are divisible by t ...

  9. C语言实现天气信息管理系统

    这篇文章主要介绍了C语言实现天气信息管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 本文实例为大家分享了C语言实现天气信息管理系统的具体代码,供大家参考,具体内 ...

  10. Python--安装 PyQt5, pyqt5-tools

    # 使用豆瓣镜像源 anaconda prompt界面里输入: pip install pyqt5-tools -i https://pypi.douban.com/simple/