礼物
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那说明这两个数是合法的一对
正解:
首先我们图文结合(如下图)
首先我们把nnn按kkk来分(第2步)
然后我们把n/kn/kn/k定为xxx
每一个k中都有一个被整除的(第3步右侧),那x个被整除的,可以组成(x−1)∗x2\frac{(x-1)*x}{2}2(x−1)∗x对
然后剩下的k−1k-1k−1我们分为奇偶数(第4步)
奇数:把中间除外的互相相乘,得到h∗x∗xh*x*xh∗x∗x对(h为一半,每个余数都有x个数,两个就有x∗xx*xx∗x对),然后剩下的一个(第5步)和其他k中的中间相乘,得到(x−1)∗x2\frac{(x-1)*x}{2}2(x−1)∗x对
偶数:直接相乘
然后处理余数:
不到一半或在一般前面的部分就直接和另一侧的x个数相配(第6步)
如果有中间1块就和前面xxx个中间1块相配(第8步)
大于一半的就和一半前的x+1x+1x+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;
}