bzoj2393 Cirno的完美算数教室

来源:互联网 发布:软件著作权查询 编辑:程序博客网 时间:2024/04/29 13:11

2393: Cirno的完美算数教室

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 322  Solved: 194
[Submit][Status][Discuss]

Description

~Cirno发现了一种baka数,这种数呢~只含有2和⑨两种数字~~
现在Cirno想知道~一个区间中~~有多少个数能被baka数整除~
但是Cirno这么天才的妖精才不屑去数啦
只能依靠聪明的你咯。
 
 

Input

一行正整数L R 
( 1 < L < R < 10^10)
 

Output

一个正整数,代表所求的答案
 

Sample Input

1 100

Sample Output

58



容斥原理+搜索剪枝

首先我们可以预处理出1-r之间所有只由2和9构成的数,最多有2046个。如果一个数是另一个的倍数,显然是没有保留必要的,n^2检查,然后去掉其中是其他数的倍数的数。

根据容斥原理,ans=至少被一个数整除的数的数量-至少被两个数整除的数的数量+至少被三个数整除的数的数量……

然后枚举选择哪些数,这是O(2^n)的,显然会超时。

但事实证明,往往选择几个数做lcm后就会超过r的范围,所以加一个剪枝优化就可以大大降低复杂度,然后这道题就可以过了。




#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<cstring>#include<algorithm>#define F(i,j,n) for(int i=j;i<=n;i++)#define D(i,j,n) for(int i=j;i>=n;i--)#define ll long long#define maxn 3005using namespace std;int cnt,tot;ll l,r,ans,a[maxn],b[maxn];bool tag[maxn];void find(ll x){if (x>r) return;a[++cnt]=x;find(x*10+2);find(x*10+9);}ll gcd(ll a,ll b){return !b?a:gcd(b,a%b);}void dfs(int x,int flag,ll t){if (x>cnt){if (t!=1) ans+=(r/t-(l-1)/t)*flag;return;}dfs(x+1,flag,t);ll tmp=t/gcd(t,a[x])*a[x];if (tmp>r) return;dfs(x+1,-flag,tmp);}int main(){scanf("%lld%lld",&l,&r);find(2);find(9);sort(a+1,a+cnt+1);F(i,1,cnt) F(j,1,i-1) if (a[i]%a[j]==0){tag[i]=1;break;}for(int i=1;a[i];i++) if (!tag[i]) b[++tot]=a[i];cnt=tot;F(i,1,cnt) a[i]=b[i];dfs(1,-1,1);printf("%lld\n",ans);}


0 0
原创粉丝点击