题意:
给你一个T,是样例的个数,接下来是五个数l1,r1,l2,r2,k 前四个数代表两个区间(l1,r1),(l2,r2)这个题l1=1,l2=1;
取x1属于(1,r1),x2属于(1,r2);
求使得gcd(x1,x2)==k 的(x1,x2)的个数,特别的(1,2)和(2,1)只计算一次;
思路:
他让求gcd等于k的 我们可以让r1,r2都除以k相当于求 取x1属于(1,r1/k),x2属于(1,r2/k); 求使得gcd(x1,x2)==1 的(x1,x2)的个数,就相当于求两个区间内互质的数可以组成几组
那么 这个题就简单了,,套上求一个区间内与一个数互质的个数的模板就A了
AC代码如下;
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <map> #include <cmath> using namespace std; typedef long long ll; const int maxn=1e6+5; vector<ll> p[maxn]; void getpri(ll kk)//这里先把每个数的素因子筛选出来,,因为这个题数据大,需要预处理一下1到1e5的素因子,防止超时 { ll x=kk; for(ll i=2;i*i<=x;i++) { if(x%i==0) { p[kk].push_back(i); while(x%i==0) x/=i; } } if(x>1)p[kk].push_back(x); } ll solve(ll x,ll r)//这里就是求一个区间内的与一个数互质的个数的模板; { ll ans=0; for(ll i=1;i<(1<<p[x].size());i++) { ll cnt=0; ll mult=1; for(ll j=0;j<p[x].size();j++) { if(i&(1<<j)) { cnt++; mult*=p[x][j]; } } mult=r/mult; if(cnt&1) ans+=mult; else ans-=mult; } if(ans<0)ans=0; if(r-ans<0)return 0; return r-ans; } int main() { int T,t=1; for(int i=1;i<maxn;i++) getpri(i); scanf("%d",&T); while(T--) { ll l1,r1,r2,l2,k; scanf("%lld%lld%lld%lld%lld",&l1,&r1,&l2,&r2,&k); if(k==0)//特别要注意这个题一个坑点,,k可能等于0!!!!!!!! { printf("Case %d: 0\n",t++); continue; } r1/=k;r2/=k; ll ans=0; if(r1>r2)swap(r1,r2);//找出大区间 for(ll i=1;i<=r2;i++)//这里遍历大区间,对于每个小于等于r1的数x1先求一下小于等于x1的与x1互质的个数,之后的x2>r1 求(1,r1)区间内与x2互质的个数
{
//比如(1,5),(1,10)
//先求(1,1)内和1互质的个数,再求(1,2)内与2互质的个数,再求(1,3)与3,再求(1,4)与4,再求(1,5)与5,后面的就是求6,7,8,9,10分别与(1,5)内互质的个数
ans+=solve(i,min(i,r1)); } printf("Case %d: %lld\n",t++,ans); } return 0; }
这个题还有另一种模板,就是深搜模板想了解一下的朋友详见
https://www.cnblogs.com/1013star/p/9896262.html