题目描述:
题意求区间[1,b],[1,d]内满足满足gcd(x,y)=k的数目。这题主要是一个转换的过程,我们可以先把两个区间都处理成[1,b/k],[1,d/k]这样就变成了求gcd(x,y)=1的数目,那么我一旦确定y,就变成了求区间内与y互素的数的个数,这样就与我上一篇博客解决的问题完全一致了,就是直接的容斥。这题需要还有需要特别处理的地方,1.区间内的数很多,所以分解因子的事要提前预处理好。2.本题(1,3)和(3,1)属于同一种方案,所以处理时为了避免重复最好限定x<y。
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<stack>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
const int MOD=1e9+7;
const int MAXM=100005;
int a,b,c,d,k;
vector<int > rec[MAXM];
bool prime[MAXM];
void init()//预处理过程。
{
memset(prime,false,sizeof(prime));
for (int i=0;i<MAXM;i++) rec[i].clear();
for (int i=2;i<MAXM;i=i+2) rec[i].push_back(2);
for (int i=3;i<MAXM;i=i+2)
{
if (!prime[i])
{
for (int j=i;j<MAXM;j=j+i)
{
prime[j]=true;
rec[j].push_back(i);
}
}
}
}
int handle(int u,int v,int w)
{
int cnt=0;
int k=1;
for (int i=0;i<rec[w].size();i++)
{
if ((1<<i)&v)
{
cnt++;
k=k*rec[w][i];
}
}
int num=u/k;
if (cnt%2) return num;
else return -num;
}
int main()
{
int T;
scanf("%d",&T);
int cas=1;
init();
while(T--)
{
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
if (k==0)
{
printf("Case %d: 0\n",cas);
cas++;
continue;
}
b=b/k;
d=d/k;
if (b>d) swap(b,d);
long long ans=0;
long long p;
for (int i=1;i<=d;i++)
{
k=min(i,b);//限定x<y。
p=0;
for (int j=1;j<(1<<rec[i].size());j++)
p=p+handle(k,j,i);
p=k-p;
ans=ans+p;
}
printf("Case %d: %I64d\n",cas,ans);
cas++;
}
return 0;
}