[SCOI2010]幸运数字

做题时间:2022.8.6

\(【题目描述】\)

求区间 \([a,b](1\leq a\leq b\leq 10^{10})\) 所有由 \(8\)\(6\) 组成的数字的倍数的个数。

\(【输入格式】\)

一行两个正整数表示 \(a,b\)

\(【输出格式】\)

一行一个整数表示答案

\(【考点】\)

容斥原理、DFS、剪枝

\(【做法】\)

首先 \(ans[a,b]=ans[1,b]-ans[1,a-1]\) ,可以去除下界限制。其次考虑 \(10^{10}\) 的以内由 \(8\)\(6\) 组成的幸运数字,发现一共有 \(2046\) 个。接下来考虑它们的倍数,由于可能一个整数同时是多个幸运数字的倍数,贡献会重复计算,考虑容斥。问题相当于 至少为1个幸运数字的倍数的数的个数 ,等价于一个交集,通过容斥原理基本柿子可知其等价于 同时为 \(1\) 个幸运数字的倍数的数的个数 \(-\) 同时为 \(2\) 个幸运数字的倍数的数的个数 \(+\) ...

同时为 \(k\) 个幸运数字的倍数的数的个数也就是 \(\lfloor b/\operatorname{lcm(a_1,a_2,...,a_k)}\rfloor\) ,其中 \(a_i\) 为幸运数字。

但是如果直接枚举所有 \(k\)\(a_i\) ,复杂度为 \(\Theta(2^{2064})\) ,吃不消。考虑剪枝:

  1. 先若一个幸运数字是另一个的倍数,那么这个幸运数字就没有枚举的必要,去除掉这些数字后,复杂度降至 \(\Theta(2^{943})\)
  2. 若当前 \(lcm>b\) 那么对答案的贡献为0 ,此时后面的数就不需要枚举了。这使得复杂度大大下降
  3. 将幸运数字从大到小排序,使得 \(lcm\) 更快地 \(>b\)

\(【代码】\)

#include<cstdio>
#include<iomanip>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1e5+50;
ll a,b;
ll num[N],ans[3];
int ed,pos=1;
void dfs(int k,int n,ll now)
{
	if(k==n+1){
		bool q=true;
		for(int i=1;i<=ed;i++){//剪枝1
			if(now%num[i]==0) q=false;
		}
		if(q) num[++ed]=now;
		return ;
	}
	dfs(k+1,n,now*10+6);
	dfs(k+1,n,now*10+8);
}
int Bit(ll b)
{
	int cnt=0;
	while(b){
		cnt++;
		b/=10;
	}
	return cnt;
}
bool cmp(ll a,ll b){return a>b;}
ll gcd(ll n,ll m){return m==0?n:gcd(m,n%m);}
void DFS(int k,int n,ll lcm,int cnt_num,ll Up)
{
	if(k==n+1){
		if(cnt_num) ans[pos]+=(cnt_num%2 ? 1 : (-1)) * (Up/lcm);
		return ;
	}
	DFS(k+1,n,lcm,cnt_num,Up);
	ll nlcm=lcm/gcd(lcm,num[k])*num[k];
	if(nlcm<=0) return ;//注意可能爆long long
	if(nlcm<=Up) DFS(k+1,n,nlcm,cnt_num+1,Up);//剪枝2
}
int main()
{
	scanf("%lld%lld",&a,&b);
    
    //算出与b同位的幸运数字个数
	int c=Bit(b);
	for(ll i=1;i<=c;i++) dfs(1,i,0);
	
    //算ans[1,b]
	while(num[ed]>b&&ed>1) ed--;
	sort(num+1,num+1+ed,cmp);//剪枝3
    DFS(1,ed,1,0,b);
	sort(num+1,num+1+ed);
	pos++;
	
    //算ans[1,a-1]
    while(num[ed]>a-1&&ed>1) ed--;
	sort(num+1,num+1+ed,cmp);//剪枝3
	DFS(1,ed,1,0,a-1);
	
	printf("%lld\n",ans[1]-ans[2]);
	return 0;
}
posted @ 2022-08-06 11:01  lxzy  阅读(64)  评论(0)    收藏  举报