BZOJ 1853: [Scoi2010]幸运数字

1853

思路:

容斥原理

先预处理出所有的幸运数字,然后去重,然后用容斥原理求

有一个优化,从大的开始求lcm,如果大于b了就不用枚举了,这是因为两个大于1e5的乘起来就会

所以最后枚举的子集只用在小于1e5中考虑就行了,小于1e5只有很少

还有要用unsigned long long,不然会溢出

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pi acos(-1.0)
#define LL unsigned long long
//#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define rs rt<<1|1, m+1, r
#define ULL unsigned LL
#define pll pair<LL, LL>
#define pii pair<int, int>
#define piii pair<pii, int>
#define mem(a, b) memset(a, b, sizeof(a))
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define fopen freopen("in.txt", "r", stdin);freopen("out.txt", "w", stout);
//head
 
const int N = 4000;
LL a, b, ans = 0;
LL Luck[N], luck[N];
LL lcm(LL a, LL b) {
    return a / __gcd(a, b) * b;
}
void dfs(LL sum, int cnt, int pos) {
    if(sum > b) return ;
    if(pos == -1) {
        if(cnt == 0) return ;
        if(cnt&1) ans += b/sum - a/sum;
        else ans -= b/sum - a/sum;
        return ;
    } 
    dfs(sum, cnt, pos-1);
    dfs(lcm(sum, luck[pos]), cnt+1, pos-1);
} 
int main() {
    scanf("%llu %llu", &a, &b);
    a--;
    int tot = 0;
    for (int l = 1; l <= 10; l++) {
        for (int i = 0; i < (1<<l); i++) {
            for (int j = l-1; j >= 0; j--) {
                if(i&(1<<j)) Luck[tot] = Luck[tot] * 10 + 8;
                else Luck[tot] = Luck[tot] * 10 + 6;
            } 
            tot++;
        }
    }
    int cnt = 0;
    for (int i = 0; i < tot; i++) {
        bool f = true;
        for (int j = 0; j < cnt; j++) {
            if(Luck[i] % luck[j] == 0) {
                f = false;
                break;
            }
        }
        if(f) luck[cnt++] = Luck[i];
    }
    dfs(1, 0, cnt-1);
    printf("%llu\n", ans);
    return 0;
} 

猜你喜欢

转载自www.cnblogs.com/widsom/p/9694280.html