BZOJ 1853: [Scoi2010]幸运数字
思路:
容斥原理
先预处理出所有的幸运数字,然后去重,然后用容斥原理求
有一个优化,从大的开始求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; }