GCD
题目链接
题目大意
现在给你两个区间:(a,b)和(c,d)现在让你在(a,b)中求出一个x,在(c,d)中求出一个y,满足gcd(x,y)=k,x,y颠倒的看作一组相同的答案(比如(1,2)和(2,1))
题解
首先看到gcd(a,b)=k,想到gcd(a/k,b/k)=1,转化为一个互质的问题。考虑到这点,我们把c和d都除k,这样我们只需要在(a,b),(c,d)中找到一组(x,y)满足互质就可以了。
到了这里,看到题目中数据较大,O( n2 )的算法不考虑,我一开始想的是枚举x,然后用容斥原理在另外一个区间中算出与其互质的个数就行了,然而当我写完的时候,程序很不给情面地超时了….
后来看到题目给出了3000组测试数据,我需要不断计算(a,b)中数的因子3000次,于是想到了筛质数打表,然后竟然过了….
综上,筛质数加容斥原理。
代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <vector>
using namespace std;
int T,a,b,c,d,k,h;
vector<int> p[100005];
bool flag[100005];
void deal()
{
for (int i=0;i<=100000;i++) p[i].clear();
for (int i=2;i<=100000;i+=2) p[i].push_back(2);
for (int i=3;i<=100000;i+=2)
{
if (!flag[i]) for (int j=i;j<=100000;j+=i)
{
flag[j]=1;
p[j].push_back(i);
}
}
}
long long solve(int v,long long high)
{
long long t=1,l=0,sum=0;
for (long long i=1;i<(1<<p[v].size());i++)
{
t=1;l=0;
for (long long j=0;j<p[v].size();j++) if ((1<<j)&i)
{
t*=p[v][j];
l++;
}
if (l%2) sum+=high/t;
else sum-=high/t;
}
return high-sum;
}
int main()
{
deal();
int Case=1;
long long ans=0;
scanf("%d",&T);
while (T--)
{
ans=0;
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
printf("Case %d: ",Case++);
if (k==0)
{
printf("0\n");
continue;
}
b=b/k;
d=d/k;
if (b>d)
{
int p;
p=b; b=d; d=p;
}
for (int i=a;i<=b;i++) ans=ans+solve(i,d)-solv````````
(i,i-1);
printf("%I64d\n",ans);
}
return 0;
}