• BZOJ1853 [Scoi2010]幸运数字 容斥原理


    欢迎访问~原文出处——博客园-zhouzhendong

    去博客园看该题解


    题目传送门 - BZOJ1853


    题意概括

      求一个区间范围内,近似幸运数字的个数。

      定义:

      幸运数字:仅由6或者8组成的数字。

      近似幸运数字:幸运数字的正整数倍。


    题解

      我们发现幸运数字很少。

      然后,我们考虑容斥。

      我们发现原来的大整数除几次机会很小。所以记忆化dfs容斥,中途跳出。

      这样可以节省很多时间。

      然后居然过去了。


    代码

    #include <cstring>
    #include <cstdio>
    #include <cstdlib>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    typedef unsigned long long LL;
    int totluck;
    LL L,R,ans,luck[2050];
    bool alive[2050];
    void df(LL x){
    	if (x>R)
    		return;
    	if (x>0)
    		luck[++totluck]=x;
    	df(x*10+6);
    	df(x*10+8);
    }
    LL gcd(LL a,LL b){
    	return b?gcd(b,a%b):a;
    }
    void dfs(int num,int pos,LL Lcm){
    	if (pos>totluck){
    		if (num==0)
    			return;
    		if (num%2==1)
    			ans+=R/Lcm-(L-1)/Lcm;
    		else
    			ans-=R/Lcm-(L-1)/Lcm;
    		return;
    	}
    	dfs(num,pos+1,Lcm);
    	LL g=Lcm/gcd(Lcm,luck[pos]);
    	if (1.0*g*luck[pos]<=R)
    		dfs(num+1,pos+1,g*luck[pos]);
    }
    bool cmp(LL a,LL b){
    	return a>b;
    }
    int main(){
    	scanf("%llu%llu",&L,&R);
    	totluck=0;
    	df(0);
    	sort(luck+1,luck+totluck+1,cmp);
    	memset(alive,true,sizeof alive);
    	for (int i=1;i<totluck;i++)
    		for (int j=i+1;j<=totluck&&alive[i];j++)
    			if (luck[i]%luck[j]==0)
    				alive[i]=0;
    	int to=0;
    	for (int i=1;i<=totluck;i++)
    		if (alive[i])
    			luck[++to]=luck[i];
    	totluck=to;
    	ans=0;
    	dfs(0,1,1);
    	printf("%llu
    ",ans);
    	return 0;
    }
    

      

  • 相关阅读:
    项目积累——导出数据
    项目积累——POPUP
    项目积累——jQuery
    项目积累——集合相关知识
    项目积累——关于时间显示和格式的几种方式
    项目积累——综合
    项目积累——js应用
    项目积累——CSS应用

    平衡二叉树
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ1853.html
Copyright © 2020-2023  润新知