【UVa#10325】The Lottery

Description

UVa#10325

给定n和m个数,求1~n中不被这m个数中任意一个数整除的数的个数

Solution

容斥原理

假设现在求1~n中被这a,b中任意一个数整除的数的个数

这个区间中能被a整除的数的个数是$\lfloor\frac{n}{a}\rfloor$

同理,能被b整除的数的个数是$\lfloor\frac{n}{b}\rfloor$

那么被a,b两个数中任意一个数整除的数有$\lfloor\frac{n}{a}\rfloor+\lfloor\frac{n}{b}\rfloor-\lfloor\frac{n}{lcm(a,b)}\rfloor$

这是因为a,b的公倍数会被多算一次,a,b的公倍数一共有$\lfloor\frac{n}{lcm(a,b)}\rfloor$个

推广到m个数上

被这m个数中的任意一个数整数的数的个数就是

被任意一个数整除的个数-被任意两个数的公倍数整除的个数+被任意三个数的公倍数整除的数的个数-……

那么我们枚举一下,然后利用容斥原理就可以了

最后用总数减去结果就是答案了

时间复杂度$O(2^{m}\times m)$

Code

#include <bits/stdc++.h>
namespace shl {
    typedef long long ll;
    int a[20];
    int n, m;
    ll ans;
    ll gcd(ll a, ll b) {
        if (!b) return a;
        return gcd(b, a % b);
    }
    ll lcm(ll a, ll b) {
        return a / gcd(a, b) * b;
    }
    int main() {
        while (~scanf("%d%d", &n, &m)) {
            memset(a, 0, sizeof(a));
            ans = n;
            int num;
            for (register int i = 1; i <= m; ++i)
                scanf("%d", &a[i]);
            int full = 1 << m;
            for (register int i = 1; i < full; ++i) {
                num = 0;
                ll sum = 1ll;
                for (register int j = 0; j < m; ++j)
                    if (i & (1 << j)) {
                        num++;
                        sum = lcm(sum, a[j + 1]);
                    }
                if (num & 1) ans -= n / sum;
                else ans += n / sum;
            }
            printf("%lld\n", ans);
        }
        return 0;
    }
};
int main() {
    shl :: main();
    return 0;
}

 

$\lfloor\frac{n}{a}\rfloor$

posted @ 2019-08-20 14:28  AD_shl  阅读(334)  评论(0编辑  收藏  举报