• HDU1695:GCD(容斥原理+欧拉函数+质因数分解)好题


    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1695

    题目解析:

    Given 5 integers: a, b, c, d, k, you're to find x in a...b, y in c...d that GCD(x, y) = k.

    题目又说a==c==1,所以就是求[1,b]与[1,d]中gcd等于k的个数,因为若gcd(x,y)==z,那么gcd(x/z,y/z)==1,又因为不是z的倍数的肯定不是,所以不是z的倍数的可以直接去掉,所以只要将b和d除以k,然后就转化成了求两个范围中互质的对数了。即求[1,b/k],与[1,d/k]中互质的数目,让b<d,又因为 (x=5, y=7) and (x=7, y=5) are considered to be the same. 

    所以先求[1,b/k]中互质的数目,即phi[1]+phi[2]+phi[3].....+phi[b/k](其中phi[i]为i的欧拉函数值),再从区间[b/k+1,d/k]枚举与区间[1,b/k]中互质的数目。其中求与区间[1,b/k]中互质的数目可以通过容斥原理求得与区间[1,b/k]中不互质的数目,相减便可以求得结果。这题折腾了一中午,一直TLE,代码在后面贴了,之后看大神的博客知道了哪里超时的原因,每个数的质因子可以在打表求欧拉函数的时候顺便求出来,一种哈希的思想,这样就不用在枚举的时候每一个数在求一遍他的质因子了,好题!

    代码如下:(608ms)

    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <queue>
    #include <math.h>
    using namespace std;
    typedef __int64 ll;
    ll sum,phi[100010];
    int cnt[100010][11],f[100010],a,b,c,d,x;
    void init()
    {
        memset(f,0,sizeof(f));
        for(int i=1; i<=100000; i++)
        {
            phi[i]=0;
            f[i]=0;
        }
        phi[1]=1;
        for(int i=2; i<=100000; i++)
        {
            if(!phi[i])
            {
                for(ll  j=i; j<=100000; j+=i)
                {
                    if(!phi[j]) phi[j]=j;
                    phi[j]=phi[j]/i*(i-1);
                    cnt[j][f[j]++]=i;//算是哈希吧,很精辟啊,这种写法要学习
                }
            }
            phi[i]+=phi[i-1];
        }
    }
    ll gcd(ll A,ll B)
    {
        return B==0?A:gcd(B,A%B);
    }
    void dfs(ll now,ll num,ll lcm,ll &coun,int key)
    {
        lcm=cnt[key][now]/gcd(cnt[key][now],lcm)*lcm;
        if(num&1)
        {
            coun+=b/lcm;
        }
        else
        {
            coun-=b/lcm;
        }
        for(ll i=now+1; i<f[key]; i++)
            dfs(i,num+1,lcm,coun,key);
    }
    int main()
    {
        int T,K=0;
        init();
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d%d%d%d",&a,&b,&c,&d,&x);
            if(x == 0 || x > b || x > d)
            {
                printf("Case %d: 0
    ",++K);
                continue;
            }
            b/=x;
            d/=x;
            sum=0;
            if(b>d) swap(b,d);
            sum+=phi[b];
            for(int i=b+1; i<=d; i++)
            {
                ll coun=0;
                for(int j=0; j<f[i]; j++)
                {
                    dfs(j,1,cnt[i][j],coun,i);
                }
                sum+=(b-coun);
            }
            printf("Case %d: %I64d
    ",++K,sum);
        }
        return 0;
    }

    TLE的:(TLE了一中午 3000ms++)

    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <queue>
    #include <math.h>
    using namespace std;
    typedef __int64 ll;
    ll a,b,c,d,x,sum,top,cnt[100010],we;//********
    int phi[100010],su[100010],prime[100010];
    void init()
    {
        we=0;
        prime[we++]=2;
        su[0]=su[1]=0;
        su[2]=1;
        for(int i=3; i<100005; i++)
            if(i%2==0) su[i]=0;
            else su[i]=1;
        double t=sqrt(100005*1.0);
        for(ll i=3; i<=t; i++)
        {
            if(su[i])
            {
                for(ll j=i*i; j<100005; j=j+i)
                {
                    su[j]=0;
                }
            }
        }
        for(ll i=3; i<=100003; i++)
        {
            if(su[i]) prime[we++]=i;
        }
        memset(phi,0,sizeof(phi));
        phi[1]=1;
        for(ll i=2; i<=100003; i++)
        {
            if(!phi[i])
            {
                for(ll  j=i; j<=100003; j+=i)
                {
                    if(!phi[j]) phi[j]=j;
                    phi[j]=phi[j]/i*(i-1);
                }
            }
        }
    }
    ll gcd(ll A,ll B)
    {
        return B==0?A:gcd(B,A%B);
    }
    void dfs(ll now,ll num,ll lcm,ll &coun)
    {
        lcm=cnt[now]/gcd(cnt[now],lcm)*lcm;
        if(num&1)
        {
            coun+=b/lcm;
            //printf("hsum======%I64d
    ",sum);
        }
        else
        {
            coun-=b/lcm;
        }
        for(ll i=now+1; i<top; i++)
            dfs(i,num+1,lcm,coun);
    }
    void cal(ll key,ll &coun)
    {
        top=0;
        ll KK=0;
        for(ll i=prime[0]; i<=key; i=prime[++KK])
        {
            if(key%i==0)
            {
                cnt[top++]=i;
                key/=i;
                while(key%i==0)
                    key/=i;
            }
        }
        if(key!=1)
        {
            cnt[top++]=key;
        }
        for(ll i=0; i<top; i++)
        {
            dfs(i,1,cnt[i],coun);
        }
    }
    int main()
    {
        int T,K=0;
        init();
        scanf("%d",&T);
        while(T--)
        {
            scanf("%I64d%I64d%I64d%I64d%I64d",&a,&b,&c,&d,&x);
            if(x == 0 || x > b || x > d)
            {
                printf("Case %d: 0
    ",++K);
                continue;
            }
    
            b/=x;
            d/=x;
            sum=0;
            if(b>d) swap(b,d);
            //cout<<"b=="<<b<<" "<<"d=="<<d<<endl;
            for(int i=1; i<=b; i++)
            {
                sum+=phi[i];
            }
            //cout<<"sumsss=="<<sum<<endl;
            for(ll i=b+1; i<=d; i++)
            {
                if(su[i])
                {
                    sum+=b;
                    continue;
                }
                ll coun=0;
                cal(i,coun);
                sum+=(b-coun);
            }
            printf("Case %d: %I64d
    ",++K,sum);
        }
        return 0;
    }
  • 相关阅读:
    Log4net.config
    ASCII 转换帮助类
    维吉尼亚加密与解密
    nginx配置说明
    验证码
    css 设置下拉菜单
    输出一张自定义文字的图片
    mvc 自定义分页控件
    【模块化】export与export default在一个文件里共存,引入时需注意的地方
    【uniapp】兼容刘海屏底部安全区
  • 原文地址:https://www.cnblogs.com/zhangmingcheng/p/4248255.html
Copyright © 2020-2023  润新知