A题
思路:题目意思是选一个重量值使得第一个人赢,那么如果有一个人力量大于等于第一个人且耐力大于等于第一个人则第一个人必输输出 -1
如果没有这样的人则第一个人必赢,题目要求输出任意允许第一个人赢的重量值,那么我们只需要输出第一个人的力量值即可
#include <stdio.h>
int max(int a, int b)
{
return a > b ? a : b;
}
int main()
{
int t;
scanf("%d", &t);
while (t--) //t 组测试样例
{
int n;
scanf("%d", &n); //n 个人
int firstPower, firstEndurance;
scanf("%d %d", &firstPower, &firstEndurance); //第一个人的力量和耐力
int maxEndurance = 0; //记录力量大于第一个人的人中耐力最大的人的耐力
for (int i = 2; i <= n; i++)
{
int power, endurance;
scanf("%d %d", &power, &endurance);
if (power >= firstPower) //如果力量大于第一个人的力量
{
maxEndurance = max(maxEndurance, endurance);
}
}
if (maxEndurance >= firstEndurance) //如果有人力量大于等于第一个人且耐力大于第一个人则第一个人必输
{
printf("-1\n");
}
else
{
printf("%d\n", firstPower);
}
}
return 0;
}
B题
思路:首先可以看出每一斜列的数的数量与列数相等,即第i斜列有i个数。那么我们可以定义一个变量t从第一列开始加上每一列的数量i,直到t>n为止,这时我们可以看出看出n与t的差即为n在第i列中的某一个,但由题目得每一列有时从左下到右上,有时从右上到左下。
我们可以画图看出i为奇数时第i列是左下到右上,i为偶数时第i列是从右上到左下,故可判断出n为第i列的中哪一个
#include <stdio.h>
int main() {
int n;
scanf("%d", &n);
int t = 0, i = 1; //t从第一列开始逐加
while (t < n) {
t += i;
i++;
}
i--;
int d = t - n;
if (i % 2 == 0) {
printf("%d/%d\n", i - d, 1 + d); //i为偶数时即右上往左下数第d个
} else {
printf("%d/%d\n", 1 + d, i - d); //i为奇数时即左下往右上数第d个
}
return 0;
}
C题
思路:
因为数据范围有点大,运算之后可能超过int的数据范围,所以都用longlong。
由题可知取的h越大需要的水量越大,由此单调性可用二分法解决该题。
最先从1到无限大中取一个中间值判断该值是否满足补充水的要求,如果能满足要求那么继续往右区间寻找更大的h,如果不满足要求那么往左区间寻找满足条件的h
#include <stdio.h>
long long a[200010];
long long n, x;
bool check(long long h)
{
long long res = 0;
for (int i = 1; i <= n; i++) // 遍历每个数
{
if (a[i] < h) // 如果小于 h,需要补充水
{
res += h - a[i];
}
if (res > x) // 如果补充的水超过了 x,说明不满足条件
return false;
}
return true; // 否则满足条件
}
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
scanf("%d%d", &n, &x);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
long long l = 1, r = 0x3f3f3f3f3f3f3f3f;//0x3f3f3f3f3f3f3f3f 对应十进制是 4557430888798830399,是一个很大的数
while (l < r)
{
long long mid = (l + r + 1) / 2; // 二分查找取中间值
if (check(mid)) // 检查是否满足条件
l = mid; // 满足条件则更新左边界
else
r = mid - 1; // 不满足条件则更新右边界
}
printf("%lld\n", l);
}
}
D题
思路: