【数学】礼物(jzoj 2129)

礼物

jzoj 2129

题目大意

有1……n,n个礼物盒,第i个礼物盒有i个礼物,现在让你选2个礼物盒,使他是k的倍数

输入样例

1 1
3 2
5 2
50 50
0 0

输出样例

0
1
4
24

数据范围

20%的数据N<=100;
80%的数据K<=1000;
每个输入文件最多有200行输入数据。

解题思路:

对于20%的数据,我们可以直接暴力
对于80%的数据,我们可以按%k得到的值来分类,如果两个数%剩的值加在一起等于k那说明这两个数是合法的一对
正解:
首先我们图文结合(如下图)
首先我们把 n n n k k k来分(第2步)
然后我们把 n / k n/k n/k定为 x x x
每一个k中都有一个被整除的(第3步右侧),那x个被整除的,可以组成 ( x − 1 ) ∗ x 2 \frac{(x-1)*x}{2} 2(x1)x
然后剩下的 k − 1 k-1 k1我们分为奇偶数(第4步)
奇数:把中间除外的互相相乘,得到 h ∗ x ∗ x h*x*x hxx对(h为一半,每个余数都有x个数,两个就有 x ∗ x x*x xx对),然后剩下的一个(第5步)和其他k中的中间相乘,得到 ( x − 1 ) ∗ x 2 \frac{(x-1)*x}{2} 2(x1)x
偶数:直接相乘
然后处理余数:
不到一半或在一般前面的部分就直接和另一侧的x个数相配(第6步)
如果有中间1块就和前面 x x x个中间1块相配(第8步)
大于一半的就和一半前的 x + 1 x+1 x+1相配(+1是因为第6步使一半前的加上了1)
注:解题思路写地不好请见谅
在这里插入图片描述

代码:

#include<cstdio>
#define min(a,b) (a)<(b)?(a):(b)
using namespace std;
long long n,k,x,ys,h,ans;
int main()
{
	scanf("%lld %lld",&n,&k);
	while (n&&k)
	  {
	  	x=n/k;//如解题思路
	  	ys=n%k;//余数
	  	h=(k-1)/2;//减去整除部分后的一半
	  	ans=x*(x-1)/2+x*x*h;//整除部分和普通部分
	  	if ((k-1)%2) ans+=x*(x-1)/2;//奇数的中间部分
	  	if (ys>0) ans+=(min(ys,h))*x,ys-=h;//余数的左边部分
	  	if (ys>0&&(k-1)%2) ans+=x,ys--;//奇余数的中间部分
	  	if (ys>0) ans+=ys*(x+1);//余数的右边部分
	  	printf("%lld\n",ans);
	  	scanf("%lld %lld",&n,&k);
	  }
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值