「2023牛客OI 赛前集训营普及组第一场」学习求余 题解

题目描述

白浅妹妹今天学习了求余运算,她很好奇求余运算和乘法运算结合起来会是什么样子,于是她设计了这样一道题目。

给定数字 n n n,你可以任选一个数字 k k k 1 ≤ k ≤ n 1 \leq k \leq n 1kn),然后计算出 n % k n\%k n%k 的值(其中 % \% % 为求余运算),记为 q q q,请问 k × q k \times q k×q 的最大值是多少。

输入格式

输入仅包含一个正整数 n n n

输出格式

输出仅一行,一个整数表示答案。

样例

样例输入

4

样例输出

3

数据范围与提示

样例说明:选择 k = 3 k = 3 k=3,那么用 4 4 4 求余 3 3 3 得到余数 1 1 1,最终算出答案为 1 × 3 = 3 1 \times 3 = 3 1×3=3

测试点 1 − 5 1-5 15 n ≤ 1000 n \leq 1000 n1000

测试点 6 − 7 6-7 67 n ≤ 1 0 6 n \leq 10^6 n106

测试点 8 − 10 8 − 10 810 n ≤ 2 × 1 0 9 n \leq 2 \times 10^9 n2×109

思路及部分实现

上来先写个暴力,然后看着 n ≤ 2 × 1 0 9 n \leq 2 \times 10^9 n2×109 微妙的数据范围陷入沉思 … \dots … \dots

long long maxn=0;
for(int i=2;i<n;i++)
	maxn=max(maxn,n%i*i);
printf("%lld",maxn);

试图强行优化结果 70 70 70 分,彻底疯狂。

long long maxn=0;
for(int i=2,j=n-1;j-i>=0;i++,j--)
	maxn=max(maxn,max(n%i*i,n%j*j));
printf("%lld",maxn);

这大抵是道数学题吧。
模拟输出了一下,看到显示框的一瞬间我直接就汗毛耸立了,不知道读者有没有同感。

n = 20 ;
i = 1 , 20 % 1 * 1 = 0
i = 2 , 20 % 2 * 2 = 0
i = 3 , 20 % 3 * 3 = 6
i = 4 , 20 % 4 * 4 = 0
i = 5 , 20 % 5 * 5 = 0
i = 6 , 20 % 6 * 6 = 12
i = 7 , 20 % 7 * 7 = 42
i = 8 , 20 % 8 * 8 = 32
i = 9 , 20 % 9 * 9 = 18
i = 10 , 20 % 10 * 10 = 0
i = 11 , 20 % 11 * 11 = 99
i = 12 , 20 % 12 * 12 = 96
i = 13 , 20 % 13 * 13 = 91
i = 14 , 20 % 14 * 14 = 84
i = 15 , 20 % 15 * 15 = 75
i = 16 , 20 % 16 * 16 = 64
i = 17 , 20 % 17 * 17 = 51
i = 18 , 20 % 18 * 18 = 36
i = 19 , 20 % 19 * 19 = 19
i = 20 , 20 % 20 * 20 = 0
maxn = 99 ( i = 11 ) ;

答案不正不好就在中间的位置,且最大值的上一个数字与最大值相比突然相差很多, i i i 继续增加后运算的结果又越来越小,换了好几次输入都是如此,显然不是巧合,开始思考数学问题。

题目要求 k × q k \times q k×q 的最大值,我们先解决如何让 q q q n % k n \% k n%k)的值最大。注意,以下推导过程中使用的变量含义均为在 a % b = c a \% b=c a%b=c 这个式子中的含义。先试着把中间值当作界限分为两部分进行分类讨论:

  • b > 1 2 a b > \frac{1}{2}a b>21a 时,由于两者的商不可能大于等于 2 2 2,则 a = b + c a=b+c a=b+c,这时要想使 c c c 的值最大,只需让 b b b 的值最小,因此 b = 1 2 a + 1 b=\frac{1}{2}a+1 b=21a+1
  • b = 1 2 a b = \frac{1}{2}a b=21a 时,运算结果必定为 0 0 0,因此不做考虑
  • b < 1 2 a b < \frac{1}{2}a b<21a 时,两者的商至少为 2 2 2,运算结果不可能大于 b > 1 2 a b > \frac{1}{2}a b>21a 的情况,同样不做考虑

解决了 q q q 的最大值的同时也确定了 k k k(即 b b b),题目到这里也就基本结束。代码实现如下:

long long ans=n%(n/2+1)*(n/2+1);
//不管奇偶性如何,k都取n/2+1,比如 4取3,5同样取3

完整代码

#include<iostream>
using namespace std;
int main(){
	long long n;
	scanf("%lld",&n);
	long long ans=n%(n/2+1)*(n/2+1);
	printf("%lld",ans);
	return 0;
}
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值