yukicoder No.316 もっと刺激的なFizzBuzzをください
問題概要
a,b,cのどれかの倍数になる数字の個数を求める。
解法
包徐原理で解く。高1のどっかでやる3つの場合の公式を使えば解くことができる。 wikipediaの3つの有限集合に対して書かれている公式をそのまま使えばいい。
集合a,b,cの数を求めるには、単に、nをa,b,cで割ればいい。このときに、1からnまでaで割れる数がいくつかるかをループでやろうとするとnが大きいので、TLEしてしまうので注意。次に、2つ含まれた集合a∧b,b∧c,c∧aについてである。集合a∧bについて考える。つまり、aの倍数でもあり、bの倍数でもある数の集合である。これをどのように考えるかであるが、 aの倍数でもあり、bの倍数でもある最小の数は、aとbのlcm。よって、lcmの倍数がnまで含まれる個数が、a∧bの集合の個数なる。同様にほかの2個の場合もできる。あとは、集合a∧b∧cの集合の数。これも2つの時と同じように考えて、a,b,cのlcmを求めて計算すればいい。あとは求まった数を包徐原理の公式に突っ込めばいい。
ミス
fizzbizzという文字列をTLで見たので解いた。 ∧(かつ)の意味で書いた。
コード
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; typedef long long ll; #define rep(i,n) for(int i=0;i<(n);i++) ll lcm(ll d1, ll d2){ return d1 / __gcd(d1, d2) * d2; } int main(void){ ll n, a, b, c; cin >> n >> a >> b >> c; ll ua = n / a; ll ub = n / b; ll uc = n / c; ll uab = n / lcm(a, b); ll ubc = n / lcm(b, c); ll uca = n / lcm(c, a); ll uabc = n / lcm(a, lcm(b, c)); printf("%lld\n", ua + ub + uc - uab - ubc - uca + uabc); return 0; }