NOMURA プログラミングコンテスト2022(AtCoder Beginner Contest 253)D - FizzBuzz Sum Hard
問題の要約
1以上N以下の整数であって、Aの倍数でもBの倍数でもないものの総和を求めよ。
制約
1<=N,A,B<=10^9
入力
N A B
考え方
1,1からNの総和を求める。これはN*(N+1)/2で求めることができる。
2,上の数からAの倍数の総和を引く。Aの倍数の総和はN/A*(N/A+1)/2*Aで求めることができる。
3,上の数からBの倍数の総和を引く。Bの倍数の総和はN/B*(N/B+1)/2*Bで求めることができる。
4,上の数からAの倍数かつBの倍数の倍数(AとBの最小公倍数の倍数)の総和を足す。AとBの最小公倍数lcm_numの総和はN/lcm_num*(N/lcm_num+1)/2*lcm_numで求めることができる。
5,答えを出力する。
(注)倍数の総和は簡単な例で導出可能である。
例えば、3の倍数は3,6,9,12,...となるが、これは3をくくりだせば、3*(1,2,3,4,...)となるので、1からNまでの総和がわかっていれば、ある程度簡単に導出できる。
あとはNまで何個の倍数があればよいか分かればよい。
例えば、3の倍数で10までだと3,6,9の3つだけだが、これはfloor(10/3)で求めることができる。
実際のプログラム
#include<iostream>
#include<numeric>
using namespace std;
int main(){
long long N,A,B;
cin >> N >> A >> B;
if(A > B){
swap(A,B);
}
long long sum = N*(N+1)/2;
sum -= N/A*(N/A+1)/2*A;
sum -= N/B*(N/B+1)/2*B;
long long lcm_num = lcm(A,B);
sum += N/lcm_num*(N/lcm_num+1)/2*lcm_num;
cout << sum << endl;
return 0;
}