• [BZOJ2393] Cirno的完美算数教室(dfs+容斥原理)


    传送门

    先通过dfs预处理出来所有只有2和9的数,也就大概2000多个。

    想在[L,R]中找到是这些数的倍数的数,可以通过容斥原理

    那么如果a % b == 0,那么便可以把 a 去掉,因为 b 的倍数肯定包括 a 的倍数,那么就会只剩500多个数

    然后我们dfs枚举所有数的可能,并顺便求出他们之间的lcm,选出来的数的个数,如果是奇数就对答案有正的贡献,如果是偶数就对答案有负的贡献

    期间如果最小公倍数lcm>R的话就直接return,这个剪枝能省去大部分时间,以至AC

    而在[L,R]区间的答案就是ans[1,R] - ans[1,L-1]

    #include <cstdio>
    #include <algorithm>
    #define N 10001
    #define LL long long
    
    int n, cnt = -1;
    LL l, r, ans, f[N], num[N];
    
    inline LL gcd(LL x, LL y)
    {
    	return !y ? x : gcd(y, x % y);
    }
    
    inline void dfs(LL v)
    {
    	if(v > r) return;
    	num[++cnt] = v;
    	dfs(v * 10 + 2);
    	dfs(v * 10 + 9);
    }
    
    inline void dfs_again(int i, int c, LL lcm)
    {
    	if(i == n + 1)
    	{
    		if(c & 1) ans += r / lcm - (l - 1) / lcm;
    		else if(c) ans -= r / lcm - (l - 1) / lcm;
    		return;
    	}
    	dfs_again(i + 1, c, lcm);
    	LL tmp = lcm * f[i] / gcd(lcm, f[i]);
    	if(tmp <= r) dfs_again(i + 1, c + 1, tmp);
    }
    
    int main()
    {
    	int i, j;
    	scanf("%lld %lld", &l, &r);
    	dfs(0);
    	for(i = 1; i <= cnt; i++)
    	{
    		if(!num[i]) continue;
    		f[++n] = num[i];
    		for(j = i + 1; j <= cnt; j++)
    			if(num[j] % num[i] == 0) num[j] = 0;
    	}
    	std::sort(f + 1, f + n + 1);
    	dfs_again(1, 0, 1);
    	printf("%lld
    ", ans);
    	return 0;
    }
    

      

  • 相关阅读:
    flex布局
    redis持久化的四种方式
    list all index in elasticsearch
    Java Thread停止关闭
    关于线程的一些操作方法
    将redis key打印到文本
    spout和bolt
    java读取redis的timeout异常
    storm中,ack与fail
    好文要收藏(大数据)
  • 原文地址:https://www.cnblogs.com/zhenghaotian/p/7663346.html
Copyright © 2020-2023  润新知