卧薪尝胆,厚积薄发。
SCOI2010 幸运数字
Date: Wed Aug 01 15:31:52 CST 2018 In Category: NoCategory

Description:

求 $[l,r]$ 中是只含 $6$ 和 $8$ 的数的倍数的数的个数。
$1\le l\le r \le 10^{10}$

Solution:

先预处理出只由 $6$ 和 $8$ 组成的数,然后去掉所有一个数是另一个数的倍数,然后 $dfs$ 容斥即可,注意为了防止爆 $long\ long$ 要在中途转一下 $double$ 判断。注意每次用 $lcm$ 更新。还要将所有数倒序排序使得 $lcm$ 能更快突破上界。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
typedef unsigned long long ll;
ll l,r;
ll tot = 0;
ll s[2050];
bool tag[2050];
ll a[2050],siz = 0;
void pre(ll k)
{
if(k > r)return;
if(k > 0)s[++tot] = k;
pre(k * 10 + 6);
pre(k * 10 + 8);
return;
}
inline ll gcd(ll a,ll b){return (b == 0 ? a : gcd(b,a % b));}
inline ll lcm(ll a,ll b){return a / gcd(a,b) * b;}
ll res;
void calc(int pos,ll bord,ll cur,ll tag)
{
if(cur > bord)return;
if(pos == siz + 1)
{
res += tag * (bord / cur);
return;
}
calc(pos + 1,bord,cur,tag);
if((double)cur / (double)gcd(cur,a[pos]) * (double)a[pos] <= (double)bord)calc(pos + 1,bord,lcm(cur,a[pos]),-tag);
return;
}
inline ll work(ll k){if(k < 6)return 0;res = 0;calc(1,k,1,1);return k - res;}
bool cmp_rev(ll a,ll b){return a > b;}
int main()
{
scanf("%lld%lld",&l,&r);
pre(0);
for(register ll i = 1;i <= tot;++i)tag[i] = true;
sort(s + 1,s + 1 + tot);
for(register ll i = 1;i <= tot;++i)
{
if(tag[i])a[++siz] = s[i];
else continue;
for(register ll j = i + 1;j <= tot;++j)
{
if(s[j] % s[i] == 0)tag[j] = false;
}
}
sort(a + 1,a + 1 + siz,cmp_rev);//!!!!!
printf("%lld\n",work(r) - work(l - 1));
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡