• [bzoj 2393] Cirno的完美算数教室 (容斥原理+dfs剪枝)


    题目描述

    CirnoCirno发现了一种bakabaka数,这种数呢只含有2299两种数字
    现在CirnoCirno想知道[L,R][L,R]中有多少个数能被bakabaka数整除
    1<L<R<10101<L<R<10^{10}

    题目分析

    由于R<1010R<10^{10},最大只有10位的数可以对答案造成贡献,每一位只能为2/9,所以最多有2000多个数,再加上把是之前的数的倍数的除去,最后只有900多个。考虑容斥,用被1个整除的-被2个整除的+被3个整除的…
    由于此时间复杂度是29002^{900},所以在dfs时剪枝就行,判断当前lcm是否大于R,同时注意lcm可能爆Longlong,还要判断小于0,否则跑不出[1,1010][1,10^{10}]这组数据(虽然也能过且R<1010R<10^{10}

    考试时想到过此做法,以为剪枝效率不高过不了,就写了大暴力去写T3了…最后只有20pts

    AC code
    #include <bits/stdc++.h>
    using namespace std;
    #define LL long long
    LL L, R, Ans, num[2500], tot;
    bool used[2500];
    
    void init()
    {
    	int Len = int(log10(R))+1;
    	for(int i = 1; i <= Len; ++i)
    		for(int j = 0; j < (1<<i); ++j)
    		{
    			LL now = 1; num[++tot] = 0;
    			for(int k = 0; k < i; ++k)
    				num[tot] += ((j&(1<<k)) ? 9 : 2) * now, now *= 10;
    			if(num[tot] > R) { tot--; continue; }
    			for(int k = 1; k < tot; ++k)
    				if(num[tot] % num[k] == 0)
    				{ tot--; break; }
    		}
    }
    
    inline LL gcd(LL a, LL b) { return b ? gcd(b, a%b) : a; }
    
    inline void dfs(int now, int cf, LL tmp) //当前数的编号,容斥系数,当前lcm
    {
    	if(tmp > R || tmp <= 0) return;
    	if(now > tot)
    	{
    		if(tmp == 1) return;
    		Ans += cf * (R/tmp - L/tmp);
    		return;
    	}
    	dfs(now+1, cf, tmp);
    	dfs(now+1, -cf, tmp/gcd(tmp,num[now])*num[now]);
    }
    
    int main ()
    {
    	scanf("%lld%lld", &L, &R), --L, init(), dfs(1, -1, 1);
    	printf("%lld
    ", Ans);
    }
    
  • 相关阅读:
    SQL SERVER 慢查询检查语句
    Bootstrap Table表头多一行
    继承方法给页面加上Session判断的小例子
    TreeView隐藏指定节点的CheckBox
    再次解决 尝试加载 Oracle 客户端库时引发 BadImageFormatException
    ASP.NET的路由系统:根据路由规则生成URL【转】
    ASP.NET的路由系统:路由映射 【转】
    ASP.NET的路由系统:URL与物理文件的分离【转】
    pycham中使用mysqldb(python2.7)
    Pyhton配置CGI
  • 原文地址:https://www.cnblogs.com/Orz-IE/p/12039470.html
Copyright © 2020-2023  润新知