P2567 [SCOI2010]幸运数字
爆搜+容斥+剪枝
从最大的开始搜,会更快突破界限。
一个的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\n", 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;
}
    希望我们都有一个光明的未来
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号