• 数论 + 容斥


    problem's Link

    mean

    给定五个数a,b,c,d,k,从1~a中选一个数x,1~b中选一个数y,使得gcd(x,y)=k.

    求满足条件的pair(x,y)数.

    analyse

    由于b,d,k都是1e5数量级的,普通枚举必定超时.

    首先可以把b,d都同时除以k,问题就转化成了求1~b/k和1~d/k中的gcd(i,j)=k的对数.

    证明如下:

    令Ai∈{1,2,3...b},Bi∈{1,2,3...d}.

    如果有:GCD(Ai,Bi)=k

    则有:GCD(Ai/k,Bi/k)=1

    而对于不能够被k整除的数,不可能有GCD(Ai,Bi)=k.

    也就是说,除以K所剔除掉的数都是不满足条件的数,对最终答案没有影响.

    这样就大大优化了时间复杂度.

    然后就是对1e5以内的数进行质因数分解,使用质因数来构造容斥表.

    再枚举1~b/k之间的每一个数,利用容斥原理算出1~d/k中有多少个数与之互质即可.

    time complexity

    O(N*logN)

    code

    /*
    * this code is made by crazyacking
    * Verdict: Accepted
    * Submission Date: 2015-10-08-21.45
    * Time: 0MS
    * Memory: 137KB
    */
    #include <queue>
    #include <cstdio>
    #include <set>
    #include <string>
    #include <stack>
    #include <cmath>
    #include <climits>
    #include <map>
    #include <cstdlib>
    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <cstring>
    #define max(a,b) (a>b?a:b)
    using namespace std;
    typedef long long(LL);
    typedef unsigned long long(ULL);
    const double eps(1e-8);
    
    const int NN=100010;
    bool v[NN];
    int p[NN];
    void makePrime()
    {
         int num=-1,i,j;
         for(i=2; i<NN; ++i)
         {
               if(!v[i]) { p[++num]=i; }
               for(j=0; j<=num && i*p[j]<NN; ++j)
               {
                     v[i*p[j]]=true;
                     if(i%p[j]==0) { break; }
               }
         }
    }
    
    struct node
    {
         int fac;
         bool ti;
         node() {}
         node(int a,bool b):fac(a),ti(b) {}
    };
    vector<node> pa[NN];
    
    void pre()
    {
         int i,j,a,cnt,si;
         for(i=1; i<=100000; ++i)
         {
               a=i;
               cnt=0;
               for(j=0; j<=9672; ++j)
               {
                     if(!(a%p[j]))
                     {
                           pa[i].push_back(node(p[j],false));
                           si=pa[i].size();
                           for(int k=0; k<si-1; ++k)
                           {
                                 pa[i].push_back(node(pa[i][si-1].fac*pa[i][k].fac,!pa[i][k].ti));
                           }
                           while(!(a%p[j]))
                                 a/=p[j];
                     }
                     if(p[j]>a || a<=0) break;
               }
         }
    }
    
    
    int main()
    {
         makePrime();
         pre();
         ios_base::sync_with_stdio(false);
         cin.tie(0);
         int t;
         scanf("%d",&t);
         for(int Cas=1; Cas<=t; ++Cas)
         {
               int a,b,c,d,k,si;
               scanf("%d %d %d %d %d",&a,&b,&c,&d,&k);
               if(k==0)
               {
                     printf("Case %d: 0
    ",Cas);
                     continue;
               }
               a=b/k;
               b=d/k;
               if(a>b) swap(a,b);
               LL ans=b;
               if(a==0) ans=0;
               for(int i=2; i<=a; ++i)
               {
                     si=pa[i].size();
                     for(int j=0; j<si; ++j)
                     {
                           if(!(pa[i][j].ti))
                           {
                                 ans+=((b-i+1)-b/pa[i][j].fac+(i-1)/pa[i][j].fac);
                           }
                           else
                           {
                                 ans-=((b-i+1)-b/pa[i][j].fac+(i-1)/pa[i][j].fac);
                           }
                     }
               }
               printf("Case %d: %I64d
    ", Cas, ans);
         }
         return 0;
    }
  • 相关阅读:
    某公司面试java试题之【二】,看看吧,说不定就是你将要做的题
    BAT面试上机题从3亿个ip中找出访问次数最多的IP详解
    Android 最流行的吸顶效果的实现及代码
    postgresql某进程占用cpu资源过高,降不下来
    媳妇要转java开发,我该怎么办?
    【原创】微信公众号电影网站域名被屏蔽完美解决方案!
    java如何对List集合中的元素进行排序(请收藏)
    【转】多语言的正则表达式,我们应该掌握
    【转】app之YdbOnline说明文档
    [敏捷开发实践](0) 开始
  • 原文地址:https://www.cnblogs.com/crazyacking/p/4864980.html
Copyright © 2020-2023  润新知