Description–
圣诞节这天,某商店准备了N个礼品盒,分别用整数1-N进行编号。其中,编号为1的盒子中有一个糖果,编号为2的盒子中有2个糖果,。。。编号为N的盒子中有N个糖果。这天一早,中山幼儿园的K个小朋友一起来到这间商店。作为当天的第一批顾客,这些小朋友可以从这N个礼品盒中选出两个拿走。小朋友们商量了一会儿后决定,他们拿走的糖果并不一定要多,但是一定要能够刚好平分给每个人。即拿走的两个盒子中的糖果总数一定要使K的倍数。现在他们想知道一共有多少种方案可供选择。
Input–
每行两个正整数N和K,其中1<=N<=109,1<=K<=109。一行N=K=0
表示输入结束,这一行不用处理。
Output–
对输入中除了N=K=0外的每一行,输出一行,这一行只有一个数,即其相对应的输入所得到的方案数。
Sample Input–
1 1
3 2
5 2
50 50
0 0
Sample Output–
0
1
4
24
说明–
20%的数据N<=100;
80%的数据K<=1000;
每个输入文件最多有200行输入数据。
解题思路–
100%: (zlt)
如果有x,y,a,b,x%k == a,y%k == b,a+b == k,则(x+y)%k==0。根据这个特性,我们可以列张表,然后利用乘法原理,一一配对。然而,可以直接被k整除的,要特殊判断;k为偶数时也要特判断。
再分情况讨论:
1、k为奇数且n%k没过k一半时
2、k为奇数且n%k过k一半时
3、k为偶数且n%k没过k一半时
4、k为偶数且n%k过k一半时
代码–
#include<iostream>
#include<cstdio>
using namespace std;
long long n,k,l,t,z,x;
int main()
{
freopen("gift.in","r",stdin);
freopen("gift.out","w",stdout);
scanf("%lld%lld",&n,&k);
while (n!=0 || k!=0)
{
l=n/k;//l:长度为n的序列可以被分成l份,每份长度为k
t=n%k;//余数
z=(k-1)/2;//每一份的一半
x=l*(l-1)/2+l*l*z; //处理非↓
if ((k-1)%2) x+=l*(l-1)/2; //余数部分
if (t>0) //
{ //
if (t>=z) x+=l*z; //
else x+=l*t; //
t-=z; //处理余数部分
} //
if (t>0 && (k-1)%2) //
x=x+(l+1)*l/2-l*(l-1)/2,t--; //“+(l+1)*l/2”是因为中间有数,所以把“l*(l-1)/2”做些改动;而“-l*(l-1)/2”是因为实际上这一段是莫得匹配滴;(当然也可以x+=l)
if (t>0) x+=(l+1)*t; //
printf("%lld\n",x);
scanf("%lld%lld",&n,&k);
}
return 0;
}
不懂的可以去看lyf大佬的