题意:
让你从区间[a,b]里面找一个数x,在区间[c,d]里面找一个数y。题目上已经设定a=b=1了。问你能找到多少对GCD(x,y)=k。x=5,y=7和y=5,x=7是同一对
题解:
弄了半天才知道我得容斥原理方法卡时间了,我那个复杂度太高了。。。卧槽了
老版本的这里可以看:HDU - 4135 容斥原理
下面说一下复杂度低的容斥原理的思想
这种方法的基本思想是:先不考虑重叠的情况,把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计算的数目排斥出去,使得计算的结果既无遗漏又无重复,这种计数的方法称为容斥原理。 如果被计数的事物有A、B、C三类,那么,A类和B类和C类元素个数总和= A类元素个数+ B类元素个数+C类元素个数—既是A类又是B类的元素个数—既是A类又是C类的元素个数—既是B类又是C类的元素个数+既是A类又是B类而且是C类的元素个数。
对于这道题[1,b]转化为[1,b/k]。[1,d]转化为[1,d/k]。这样的话只需要for循环i从1到b/k,找出来区间[1,d/k]内有多少数与i互质就行了
但是要注意题目说了x=5,y=7和y=5,x=7是同一对,那这就需要去重,这一点具体见代码
代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<algorithm> 5 #include<math.h> 6 #include<queue> 7 using namespace std; 8 typedef long long ll; 9 const int maxn=100000; 10 ll v[maxn],index; 11 void oula(ll n) //获取n的所有质因数 12 { 13 index=0; 14 for(ll i=2; i<=sqrt(n); ++i) 15 { 16 if(n%i==0) 17 { 18 v[index++]=i; 19 n/=i; 20 while(n%i==0) 21 n/=i; 22 } 23 } 24 if(n>1) 25 v[index++]=n; 26 } 27 ll get_result(ll n)//容斥原理 28 { 29 ll ans=0; 30 for(ll i=1;i< (1<<index) ; i++) 31 { 32 ll ones=0,mult=1; 33 for(ll j=0;j<index;j++) 34 { 35 if(i & (1<<j)) 36 { 37 ones++; 38 mult*=v[j]; 39 } 40 } 41 if(ones&1)//奇数加,偶数减 42 ans+= n/mult; 43 else 44 ans-= n/mult; 45 } 46 return n-ans; 47 } 48 int main() 49 { 50 ll t,p=1; 51 scanf("%lld",&t); 52 while(t--) 53 { 54 ll a,b,c,d,k; 55 scanf("%lld%lld%lld%lld%lld",&a,&b,&c,&d,&k); 56 if(k==0) {printf("Case %lld: 0 ",p++);continue;}//k==0特判 57 if(b>d) swap(b,d); 58 d/=k,b/=k; 59 ll ans=0; 60 for(ll i=1;i<=b;i++)//1~b区间 61 { 62 oula(i); 63 ans+=get_result(b); 64 } 65 ans=(ans+1)/2; //这个除2就把那个 x=5,y=7和y=5,x=7是同一对 这个要求满足了 66 for(ll i=b+1;i<=d;i++)//b+1~d区间 67 { 68 oula(i); 69 ans+=get_result(b); 70 } 71 printf("Case %lld: %lld ",p++,ans); 72 } 73 return 0; 74 }