zoukankan      html  css  js  c++  java
  • BZOJ2393 & 1853 [Scoi2010]幸运数字 【搜索 + 容斥】

    题目

    在中国,很多人都把6和8视为是幸运数字!lxhgww也这样认为,于是他定义自己的“幸运号码”是十进制表示中只包含数字6和8的那些号码,比如68,666,888都是“幸运号码”!但是这种“幸运号码”总是太少了,比如在[1,100]的区间内就只有6个(6,8,66,68,86,88),于是他又定义了一种“近似幸运号码”。lxhgww规定,凡是“幸运号码”的倍数都是“近似幸运号码”,当然,任何的“幸运号码”也都是“近似幸运号码”,比如12,16,666都是“近似幸运号码”。 现在lxhgww想知道在一段闭区间[a, b]内,“近似幸运号码”的个数。

    输入格式

    输入数据是一行,包括2个数字a和b

    输出格式

    输出数据是一行,包括1个数字,表示在闭区间[a, b]内“近似幸运号码”的个数

    输入样例

    【样例输入1】

    1 10

    【样例输入2】

    1234 4321

    输出样例

    【样例输出1】

    2

    【样例输出2】

    809

    提示

    【数据范围】
    对于30%的数据,保证1 < =a < =b < =1000000
    对于100%的数据,保证1 < =a < =b < =10000000000

    题解

    考虑容斥原理

    a以内一些数的倍数的数量 = 取一个数倍数的数量 - 取两个数的公倍数的数量 + 数三个数公倍数的数量........

    我们先预处理出所有的幸运数字,再筛去有倍数关系的,得到互质的幸运数字
    用搜索将其组合,分组合的奇偶对答案进行贡献
    稍加一些剪枝:
    ①超过r就回溯
    ②从大到小枚举,尽早回溯

    可以顺便把2393A了
    值得一提的是,1853比2393要难,因为2393实际范围为(10^9)不会爆long long,而1853会爆long long,要先用double储存判断一下

    #include<iostream>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
    using namespace std;
    const int maxn = 10005,maxm = 100005,INF = 1000000000;
    LL q[maxn],a[maxn],qi,l,r,n;
    LL ans = 0;
    bool vis[maxn];
    LL gcd(LL a,LL b){return b ? gcd(b,a % b) : a;}
    void dfs1(LL x){
    	if (x > r) return;
    	if (x) q[++qi] = x;
    	dfs1(x * 10 + 6); dfs1(x * 10 + 8);
    }
    void dfs(int pos,int t,LL num){
    	if (pos > n){
    		if (t & 1) ans += r / num - (l - 1) / num;
    		else if (t) ans -= r / num - (l - 1) / num;
    		return;
    	}
    	dfs(pos + 1,t,num);
    	double x = (double)a[pos] * num / gcd(a[pos],num);
    	if (x <= r) dfs(pos + 1,t + 1,(LL)x);
    }
    int main(){
    	cin>>l>>r;
    	dfs1(0);
    	sort(q + 1,q + 1 + qi);
    	for (int i = 1; i <= qi; i++){
    		if (!vis[i]){
    			a[++n] = q[i];
    			for (int j = i + 1; j <= qi; j++)
    				if (q[j] % q[i] == 0) vis[j] = true;
    		}
    	}
    	REP(i,n>>1) swap(a[i],a[n - i + 1]);
    	dfs(1,0,1);
    	printf("%lld",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    【转载】Altium Designer多图纸功能
    【原创】使用Ultra Librarian为Altium Designer 09生成元器件库
    【笔记】niosII与win7兼容性解决方法
    【转载】关于FSM
    【原创】在仿真中如何使用好parameter?
    【转载】 $dispaly()、$strobe()、$monitor() 、$fwrite()與blocking / nonblocking的關係
    【转载】使用Debussy+ModelSim快速查看前仿真波形
    将博客搬至CSDN
    perl 替换一例
    linux shell常用快捷键(转载)
  • 原文地址:https://www.cnblogs.com/Mychael/p/8323481.html
Copyright © 2011-2022 走看看