BZOJ 2393 Cirno的完美算数教室

Posted on 2016-12-18 14:59  ziliuziliu  阅读(183)  评论(0编辑  收藏  举报

就是爆搜嘛。

先从大到小排个序能减去dfs树上很大的一部分。这个技巧要掌握。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 100500
using namespace std;
long long l,r,num[maxn],s[maxn],t1=0,t2=0,t,ans=0;
bool vis[maxn];
void get_baka(long long bit,long long nums)
{
    if ((bit>t) || (nums>r)) return;
    if (nums) num[++t1]=nums;
    get_baka(bit+1,nums*10+2);
    get_baka(bit+1,nums*10+9);
}
long long gcd(long long a,long long b)
{
    if (!b) return a;
    return gcd(b,a%b);
}
long long lcm(long long a,long long b)
{
    return a*b/gcd(a,b);
}
void dfs(long long now,long long num,long long val)
{
    if (now==t2+1)
    {
        if (num!=1) ans+=((r/num)-((l-1)/num))*val;
        return;
    }
    dfs(now+1,num,val);
    long long aft=lcm(num,s[now]);
    if (aft<=r) dfs(now+1,aft,val*(-1));
}
int main()
{
    scanf("%lld%lld",&l,&r);
    t=(long long)(log(r)/log(10))+1;
    get_baka(0,0);
    sort(num+1,num+t1+1);
    for (long long i=1;i<=t1;i++)
    {
        if (vis[i]) continue;
        s[++t2]=num[i];
        for (long long j=i+1;j<=t1;j++)
        {
            if (!num[j]%num[i])
                vis[j]=true;
        }
    }
    for (int i=1;i<=t2;i++) num[i]=s[t2-i+1];
    for (int i=1;i<=t2;i++) s[i]=num[i];
    dfs(1,1,-1);
    printf("%lld\n",ans);
    return 0;
}