首页 > 代码库 > BZOJ 2393 Cirno的完美算数教室 容斥原理+DFS

BZOJ 2393 Cirno的完美算数教室 容斥原理+DFS

警告:网上的题解都是误人子弟,看此篇题解之前请将脑海中对其它写于本题解之前的网上常见题解的印象全部消除之后方可阅读

此题的数据范围是10^9 但是10^10一样可以做 不影响

首先我们可以预处理出1~r以内所有只由2和9构成的⑨数 容易发现最多有1022个

但是其中有一些⑨数是另一些的倍数 比如说a是b的倍数 那么一个数如果是a的倍数那么就一定是b的倍数 我们只需要计算b即可 无需计算a 这里可以剪枝 不剪无妨

处理出不是另一个数的倍数的所有⑨数 最多应该有466个 求区间内这些数的倍数的数的数量 可以开始容斥了

总数=是一个数的倍数的数的数量-是两个数公倍数的数的数量+是三个数公倍数的数的数量……

比如说枚举到某n个数的公倍数 就是对这n个数做一下LCM 然后用r/lcm就是1~r以内这n个数的公倍数的个数了

但是2^466枚举显然是不可能的 我们发现这466个数大多都比较大 随便选几个做一下LCM就爆r了

于是我们选择搜索 同样是2^466的复杂度 但是我们可以剪枝 当当前的LCM大于r就剪枝 剪完之后就没多少了 1s之内完全可以出解

【无脑喷人时间,不喜勿视】

TM网上的题解尼玛写的都是什么**玩应!!!谁TM说筛出来只有30个!!你们TM也不看看自己筛的是质数么!!!真要是只有30个你们为何不打表???

知不知道你们的**题解误导了多少人!!连a整除b时谁是谁的倍数都搞不清楚还来指导别人?!!能写出【if(!a[j]%a[i])】这种东西是完全没写过数论么???

真是……以前刷容斥原理的时候就看到这道题 看了题解简直不知所云 卡了我很久

在题解完全离谱的情况下还能把代码写的八九不离十真是服了

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAX 1000000000ll
using namespace std;
long long l,r,ans,a[1050],b[1050];
bool v[1050];
void DFS1(long long x)
{
	if(x>r) return;
	a[++a[0]]=x;
	DFS1(x*10+2);
	DFS1(x*10+9);
}
void DFS2(int pos=1,int flag=-1,long long now=1)
{
	if(!b[pos])
	{
		if(now^1)
			ans+=(r/now-(l-1)/now)*flag;
		return ;
	}
	DFS2(pos+1,flag,now);
	long long temp=now*b[pos]/__gcd(now,b[pos]);
	if(temp>r) return ;
	DFS2(pos+1,-flag,temp);
}
int main()
{
	int i,j,cnt=0;
	cin>>l>>r;
	DFS1(2);DFS1(9);
	sort(a+1,a+a[0]+1);
	for(i=1;a[i];i++)
		for(j=i+1;a[j];j++)
			if(a[j]%a[i]==0)
				v[j]=1;
	for(i=1;a[i];i++)
		if(!v[i])
			b[++b[0]]=a[i];
	DFS2();
	cout<<ans<<endl;
}


BZOJ 2393 Cirno的完美算数教室 容斥原理+DFS