容斥原理练习题

1. bzoj 2393&nefu 1795 Cirno的完美算数教室

http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=1795

Description
Cirno发现了一种baka数,这种数只含有2和9两种数字
现在Cirno想知道一个区间中有多少个数能被baka数整除
但是Cirno这么天才的妖精才不屑去数啦
只能依靠聪明的你咯。
Input
一行正整数L R
( 1 < L < R < 10^10)
Output
一个正整数,代表所求的答案
Sample Input
1 100
Sample Output
58

容斥原理:先求出区间内所有baka数,去掉其中是baka数倍数的那些数,因为它们的作用是等价的。区间内被一个baka数整除的个数-被2个baka数公倍数整除的+3个公倍数整除的-…
dfs也不知道写的什么,莫名其妙就过了,觉得可能林大oj数据太弱,结果在bzoj也没找到这个题…所以到底过不过,还不一定…
代码

#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
const ll maxn=1e10+5;
ll baka[2100],vis[2100];
ll l,r,ans;
int cnt,tnt;
void f(ll x)
{
    if(x>r)
        return;
    baka[cnt++]=x;
    f(x*10+2);
    f(x*10+9);
}
ll gcd(ll a,ll b)
{
    return b?gcd(b,a%b):a;
}
void dfs(ll cou,ll mul,ll sum,ll tag)
{
    if(mul>tag)
        return;
    if(sum!=0&&cou==tnt)
    {
        if(sum&1)
            ans+=tag/mul;
        else
            ans-=tag/mul;
        return;
    }
    if(cou==tnt)
        return;
    dfs(cou+1,mul,sum,tag);
    ll tmp=mul/gcd(mul,baka[cou+1])*baka[cou+1];
    dfs(cou+1,tmp,sum+1,tag);
}
ll rc(ll x)
{
    ans=0;
    dfs(-1,1,0,x);
    return ans;
}
int main()
{
    scanf("%lld%lld",&l,&r);
    f(0);
    sort(baka,baka+cnt);
    for(int i=1; i

2. bzoj 18533&nefu 1794 幸运数字-容斥

http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=1794
Description
在中国,很多人都把6和8视为是幸运数字!lxhgww也这样认为,于是他定义自己的“幸运号码”是十进制表示中只包含数字6和8的那些号码,比如68,666,888都是“幸运号码”!但是这种“幸运号码”总是太少了,比如在[1,100]的区间内就只有6个(6,8,66,68,86,88),于是他又定义了一种“近似幸运号码”。lxhgww规定,凡是“幸运号码”的倍数都是“近似幸运号码”,当然,任何的“幸运号码”也都是“近似幸运号码”,比如12,16,666都是“近似幸运号码”。 现在lxhgww想知道在一段闭区间[a, b]内,“近似幸运号码”的个数。
Input
输入数据是一行,包括2个数字a和b
Output
输出数据是一行,包括1个数字,表示在闭区间[a, b]内“近似幸运号码”的个数
Sample Input
「样例输入1」
1 10
「样例输入2」
1234 4321
Sample Output
「样例输出1」
2
「样例输出2」
809
Hint
对于100%的数据,保证1 < =a < =b < =10000000000
代码
跟上一个题一模一样,但数据太大,剪枝优化不然会超时,通过给幸运数字数组从大到小排序,这样dfs会先选择大数,则省去了许多不必要的分支。

#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
ll baka[3000],vis[3000];
ll l,r,ans;
int cnt,tnt;
void f(ll x)
{
    if(x>r)
        return;
    baka[cnt++]=x;
    f(x*10+8);
    f(x*10+6);
}
ll gcd(ll a,ll b)
{
    return b?gcd(b,a%b):a;
}
void dfs(ll cou,ll mul,ll sum,ll tag)
{
    if(mul>tag)
        return;
    if(sum!=0&&cou==tnt)
    {
        if(sum&1)
            ans+=tag/mul;
        else
            ans-=tag/mul;
        return;
    }
    if(cou==tnt)
        return;
    dfs(cou+1,mul,sum,tag);
    double tmp=(double)mul/(double)gcd(mul,baka[cou+1])*(double)baka[cou+1];
    if(tmp>r) return;
    dfs(cou+1,tmp,sum+1,tag);
}
ll rc(ll x)
{
    ans=0;
    dfs(-1,1,0,x);
    return ans;
}
bool cmp(ll a,ll b)
{
    return a>=b;
}
int main()
{
    scanf("%lld%lld",&l,&r);
    f(0);
    sort(baka,baka+cnt);
    for(int i=1; i

你可能感兴趣的:(容斥)