• #搜索,容斥#洛谷 2567 [SCOI2010]幸运数字


    题目

    问区间([l,r],l,rleq 10^{10})中有多少个数是

    数位由6或8组成的数的倍数(包括本身)


    分析

    数位由6或8组成的数最多有两千多种,
    这可以直接一遍暴搜得到
    对于区间([1,n])答案应该是(frac{n}{i}-frac{n}{i*j}+frac{n}{i*j*k})
    当选出的数的最小公倍数超过(n)可以剪枝,不会达到上界,
    但是这样远远不够,考虑若(i|j)那么(j)显然可以直接舍弃,剩下的数可以降序排序后剪枝
    然后对于超过(n/2)的数被选择只能选择自己(两数gcd至少为2),可以提前处理,这样就可以AC了


    代码

    #include <cstdio>
    #include <algorithm>
    #define rr register
    using namespace std;
    typedef long long lll; bool v[2111];
    lll b[2111],l,r,ans,sum,now,m;
    inline void Pro(lll now,lll n){
    	if (now>n) return;
    	b[++b[0]]=now;
    	Pro(now*10+6,n),
    	Pro(now*10+8,n);
    }
    inline lll gcd(lll x,lll y){return y?gcd(y,x%y):x;}
    inline void dfs(int dep,lll lcm,int cnt){
    	if (dep>m) return;
    	dfs(dep+1,lcm,cnt);
    	rr lll t=lcm*b[dep]/gcd(lcm,b[dep]);
    	if (t>now) return;
    	if (cnt&1) ans-=now/t;
    	    else ans+=now/t;
    	dfs(dep+1,t,cnt+1);
    }
    inline lll answ(lll n){
    	if (!n) return 0;
    	ans=0,now=n,dfs(1,1,0);
    	return ans;
    }
    signed main(){
    	scanf("%lld%lld",&l,&r),Pro(6,r),Pro(8,r);
    	sort(b+1,b+1+b[0]);
    	for (rr int i=1;i<=b[0];++i) if (!v[i])
    	for (rr int j=i+1;j<=b[0];++j) if (b[j]%b[i]==0) v[j]=1;
    	for (rr int i=1;i<=b[0];++i)
    	if (!v[i]){
    		if (b[i]>r/2) sum+=r/b[i]-(l-1)/b[i];
    		    else b[++m]=b[i];
    	}
    	reverse(b+1,b+1+m);
        return !printf("%lld",sum+answ(r)-answ(l-1));
    }
    
  • 相关阅读:
    ES6
    JavaScript小练习2
    JavaScript实现多重继承
    一个定高,一个高度自适应的布局
    实例教程:1小时学会Python(转)
    备份文件的python脚本(转)
    Python2.5/2.6实用教程:基础篇(转)
    Python 读写 Excel(转)
    python实用技巧 : Filtering os.walk(转)
    Python:文件操作技巧(File operation)(转)
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/14477097.html
Copyright © 2020-2023  润新知