爆搜+容斥+剪枝
从最大的开始搜,会更快突破界限。
一个的lcm-两个的lcm+三个的lcm。。。
直接大力爆就完了。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
const ll MAXN = 3010;
vector <ll> q;
ll M, N, cnt, ans;
void dfs(ll, ll);
void dfs2(ll, ll, ll);
ll calc(ll, ll, ll);
bool cmp(ll, ll);
int main() {
scanf("%lld%lld", &M, &N);
cnt = max(10LL, (ll)log10(N) + 1LL);
dfs(0, 0);
sort(q.begin(), q.end());
for (vector<ll>::iterator it = q.begin(); it != q.end(); it++) {
for (vector<ll>::iterator ip = it+1; ip != q.end(); ip++) {
if ((*ip) % (*it) == 0) {
q.erase(ip);
ip--;
}
}
}
sort(q.begin(), q.end(), cmp);
/*for (vector<ll>::iterator it = q.begin(); it != q.end(); it++) {
printf("%lld ", *it);
}*/
dfs2(0, 0, 1);
printf("%lld
", ans);
return 0;
}
void dfs2(ll ct, ll now, ll nm) {
if (nm > N) return;
if (now == (ll)q.size()) {
if (ct == 0) return;
if (ct & 1) {
ans += calc(M, N, nm);
} else {
ans -= calc(M, N, nm);
}
return;
}
ll tem = nm / __gcd(nm, q.at(now));
if ((__int128)tem * q.at(now) <= N)
dfs2(ct+1, now+1, tem * q.at(now));
dfs2(ct, now+1, nm);
}
ll calc(ll x, ll y, ll val) {
ll l = (x / val + (x % val > 0)), r = y / val;
return r - l + 1;
}
void dfs(ll n, ll sum) {
if (sum) {
q.push_back(sum);
}
if (n == cnt) return;
else {
dfs(n+1, sum * 10 + 6);
dfs(n+1, sum * 10 + 8);
}
}
bool cmp(ll a, ll b) {
return a > b;
}