题目描述
圣诞节这天,某商店准备了N个礼品盒,分别用整数1-N进行编号。其中,编号为1的盒子中有一个糖果,编号为2的盒子中有2个糖果,。。。编号为N的盒子中有N个糖果。这天一早,中山幼儿园的K个小朋友一起来到这间商店。作为当天的第一批顾客,这些小朋友可以从这N个礼品盒中选出两个拿走。小朋友们商量了一会儿后决定,他们拿走的糖果并不一定要多,但是一定要能够刚好平分给每个人。即拿走的两个盒子中的糖果总数一定要使K的倍数。现在他们想知道一共有多少种方案可供选择。
输入
每行两个正整数N和K,其中1<=N<=10^9,1<=K<=10^9。一行N=K=0
表示输入结束,这一行不用处理。
输出
对输入中除了N=K=0外的每一行,输出一行,这一行只有一个数,即其相对应的输入所得到的方案数。
样例输入
1 1
3 2
5 2
50 50
0 0
样例输出
0
1
4
24
数据范围限制
20%的数据N<=100;
80%的数据K<=1000;
每个输入文件最多有200行输入数据。
20%:
直接暴力,o(n`2)枚举每一种情况
代码如下:
var ans,i,j,x,y,l:longint;
a:array[0..1000000]of longint;
begin
assign(input,'gift.in');
assign(output,'gift.out');
reset(input);
rewrite(output);
while not eoln() do
begin
ans:=0;
l:=0;
fillchar(a,sizeof(a),#0);
readln(x,y);
if (x=0)and(y=0) then begin close(input); close(output); halt; end;
for i:=1 to x-1 do
for j:=i+1 to x do
if (i+j)mod y=0 then inc(ans);
writeln(ans);
end;
close(input);
close(output);
end.
40%:
40分就要推出简易公式,枚举n个数可能可以拼成m的倍数——z。
①当(z>x)and(((x*2)-z) mod 2=0) max:=max+(x-(z-x)) div 2
②当(z>x)and(((x*2)-z) mod 2=1) max:=max+(x-(z-x)) div 2+1
③当(z<=x)and(z mod 2=0) max:=max+z div 2-1
④当(z<=x)and(z mod 2=1) max:=max+z div 2
代码如下:
var max,x,y,z:int64;
i:longint;
begin
assign(input,'gift.in');
assign(output,'gift.out');
reset(input);
rewrite(output);
while not eoln() do
begin
max:=0;
readln(x,y);
if (x=0)and(y=0) then begin close(input); close(output); halt; end;
for i:=1 to x*2 div y do
begin
z:=i*y;
if z>=x*2 then break;
if z>x then
if (x*2-z) mod 2=0 then max:=max+(x-(z-x)) div 2
else max:=max+(x*2-z) div 2+1
else if z mod 2<>0 then max:=max+z div 2 else max:=max+z div 2-1;
end;
writeln(max);
end;
close(input);
close(output);
end.
100%:
如果有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一半时
代码如下:
var n,m,x,y,z,x1:int64;
begin
assign(input,'gift.in');
assign(output,'gift.out');
reset(input);
rewrite(output);
readln(n,m);
while (n<>0)and(m<>0) do
begin
x:=n div m;
y:=n mod m;
z:=(m-1) div 2;
x1:=x*(x-1)div 2+x*x*z;
if (m mod 2=0) then x1:=x1+x*(x-1)div 2;
if y>0 then
begin
if (y>=z) then x1:=x1+x*z else x1:=x1+x*y;
y:=y-z;
if (y>0)and(m mod 2=0)then
begin
x1:=x1-x*(x-1)div 2+x*(x+1) div 2;
y:=y-1;
end;
if (y>0) then x1:=x1+(x+1)*y;
end;
writeln(x1);
readln(n,m);
end;
close(input);
close(output);
end.