有这么一道题,在学习基础算法的初期,这一道题曾让多少萌新对于它是无从下手,只能靠循环遍历蹭时间来获取那微弱的一点点分。
问题描述
给定一个整数和N,K。三元组数(a,b,c)满足三元关系:a+b,a+c,b+c都是k的倍数。注意a,b,c的顺序不能改变,但是它们数值可以相同。请找出a,b,c均不大于N的三元组个数。
输入格式
输入两个整数N,K,中间用空格隔开。
N K
输出格式
输出三元组个数。
样例输入 3 2 样例输出 9
样例输入 5 3 样例输出 1
样例输入 31415 9265 样例输出 27
样例输入 35897 932 样例输出 114191
样例一说明:
(1,1,1),(1,1,3),(1,3,1),(1,3,3),(2,2,2),(3,1,1),(3,1,3),(3,3,1),(3,3,3)满足条件。
做法
这一道题不能用循环来找a,b,c。
思路:
找k的倍数一共有两种情况。
1 两个数都为k的倍数,那两数之和肯定为k的倍数。
2 两个数都不为k的倍数,但相加为k的倍数。
定义两个变量a,b。
其中一个用于储存在n范围内k的倍数的个数。
那么在第一种情况下,就一共有a*(a-1)*(a-2)种。
注意:这里还有一种特殊情况为其中两数相同而剩下一数不同,且都为k的倍数。
又有(a-1)*a+a 种情况。
第二个变量用来判断第二种情况,即两数除与k的余数都为k/2,那么尽管两个数都不为k的倍数,但相加为k的倍数。但在这种情况下,k必须为2的倍数才有可能。
这时有b*(b-1)*(b-2)+(b-1)*b+b 种情况。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int a,b;
int N=1000001;
ll n,k,ans;
int main(){
cin>>n>>k;
a=n/k;
b=n/k+(n%k>=k/2);
ans=(ll)a*(a-1)*(a-2)+3ll*(a-1)*a+a;
if(k%2==0)
ans+=(ll)b*(b-1)*(b-2)+3ll*(b-1)*b+b;
cout<<ans;
return 0;
}