zoukankan      html  css  js  c++  java
  • hdu1695:数论+容斥

    题目大意:

    求x属于[1,b]和 y属于[1,d]的 gcd(x,y)=k 的方案数

    题解:

    观察发现 gcd()=k 不好处理,想到将x=x/k,y=y/k 后 gcd(x,y)=1。。

    即问题转化为求区间 [1,b/k]和 [1,d/k]的互质数对个数

    由于题目规定 (x,y)和(y,x)是同一种,所以我们可以规定 x<y,,然后只需对每一个y求出比他小的即可

    公共部分可以通过欧拉函数快速求出。。

    非公共部分就不行了。。

    所以就分解质因数,用容斥的方法求了

    #include <iostream>
    #include <stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<string>
    #include<ctype.h>
    using namespace std;
    #define maxn 100000
    int isnotprime[maxn+1];
    int num[maxn+1];
    int fac[maxn+1][30];
    int prime[maxn];
    int euler[maxn+1];
    int np;
    int a,b,c,d,k,n,m;
    long long ans;
    void setprime()
    {
        np=0;
        memset(isnotprime,0,sizeof(isnotprime));
        for(int i=2;i<=1000;i++)
        {
            if(!isnotprime[i])
               prime[np++]=i;
            for(int j=0;j<np&&prime[j]*i<=1000;j++)
            {
                isnotprime[i*prime[j]]=1;
                if(i%prime[j]==0)
                    break;
            }
        }
    }
    void findfac(int x)
    {
        num[x]=0;
        int p=x;
        for(int i=0;i<np;i++)
        {
            if(p%prime[i]==0)
            {
                fac[x][num[x]++]=prime[i];
            }
            while(p%prime[i]==0)
            {
                p/=prime[i];
            }
        }
        if(p>1)
        {
            fac[x][num[x]++]=p;
        }
    }
    void setfac()
    {
        for(int i=2;i<=maxn;i++)
        {
            findfac(i);
        }
    }
    void phi()
    {
        for(int i=1;i<=maxn;i++)
            euler[i]=i;
        for(int i=2;i<=maxn;i+=2)
            euler[i]/=2;
        for(int i=3;i<=maxn;i++)
        {
            if(euler[i]==i) //未被筛到。是素数,则用此素数来筛
            {
                for(int j=i;j<=maxn;j+=i)
                {
                    euler[j]=euler[j]/i*(i-1);
                }
            }
        }
        return ;
    }
    void ini()
    {
        scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
    }
    int iae(int x)
    {
        int res=0;
        int cur,tmp;
        for(int i=1;i<(1<<num[x]);i++)
        {
            cur=1;
            tmp=0;
            for(int j=0;j<num[x];j++)
            {
                if(i&(1<<j))
                {
                    cur*=fac[x][j];
                    tmp++;
                }
            }
            if(tmp&1)
            {
                res+=m/cur;
            }
            else
            {
                res-=m/cur;
            }
        }
        return m-res;
    }
    int cas=1;
    void solve()
    {
        printf("Case %d: ",cas++);
        if(k==0)
        {
            puts("0");
            return;
        }
        m=min(b/k,d/k);
        n=max(b/k,d/k);
        ans=0;
        for(int i=1;i<=m;i++)
        {
            ans+=euler[i];
        }
        for(int i=m+1;i<=n;i++)
        {
            ans+=iae(i);
        }
        printf("%I64d
    ",ans);
    }
    int main()
    {
        setprime();
        setfac();
        phi();
        int t;
        scanf("%d",&t);
        while(t--)
        {
            ini();
            solve();
        }
        return 0;
    }
  • 相关阅读:
    spoj 694 求一个字符串中不同子串的个数
    Qt for Android 开发大坑
    HDUOJ A Mathematical Curiosity 1017
    Node.js开发入门—HelloWorld再分析
    GTK入门学习:布局容器之固定布局
    彻底领悟javascript中的exec与match方法
    JQuery中attr属性和jQuery.data()学习笔记
    正则表达式-验证带千分号的,带任意位小数的数字类型
    JQuery EasyUI 动态改变表单项的验证守则
    JavaScript计算两个日期的时间差
  • 原文地址:https://www.cnblogs.com/oneshot/p/4095989.html
Copyright © 2011-2022 走看看