数论 + 容斥 - HDU 1695 GCD

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\n",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\n", Cas, ans);
     }
     return 0;
}
复制代码
posted @   北岛知寒  阅读(455)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
历史上的今天:
2014-10-09 虚拟IP和IP漂移
点击右上角即可分享
微信分享提示
主题色彩