題目大意:給定兩個區(qū)間,[a,b] [c,d] 設x屬于第一個區(qū)間,y屬于第二個區(qū)間,求gcd(x,y)=k的實數對有多少個。
方法:對兩個區(qū)間分別除以k,轉化為求新區(qū)間內,互質的實數對有多少個。
容斥原理:|t1Ut2U...Utn| = sum[ti] - sum[ti n tj] + sum[ti n tj n tk] - ... + (-1)^(m+1)|t1 n t2 n ... n tn|
把所有有是1的倍數的點對加起來  減去既有1也有(2,3,5。。。)的點對   加上既有1也有2也有3.。的點對


#include <stdio.h>
#include 
<algorithm>
using namespace std;

bool mark[100010];
int prim[10000], tot =0, sum = 0;
struct node{
     
int v; //v存的是數  就是乘積  k是記錄減還是加
     
int k;
}tb[
70000];

void di(long long p,int k,int odd) {//奇數個因數的就加 偶數個因數的就減
     
if (k == tot) return;
     
long long tmp = p*prim[k]; 
     
if (tmp > 100000return;
     di(p,k
+1,odd);
     tb[sum].v 
= tmp;
     tb[sum
++].k = -odd;
     di(tmp,k
+1,-odd);
}

void swap(int &a,int &b) {
     a 
+= b;
     b 
= a-b;
     a 
= a-b;
}

int cmp(node a,node b) {
    
return a.v < b.v;
}

int main () {
    
int i, j;
    
for (i = 2; i <= 100000; i++) {
        
if (!mark[i]) {
           prim[tot
++= i;
           
for (j = i+i; j <= 100000; j += i)
               mark[j] 
= 1;
        }
    }
    tb[
0].v = 1; tb[0].k = 1;
    sum 
= 1;
    di(
1,0,1);
    sort(tb,tb
+sum,cmp);
    
int kase, a, b, c, d, k, o = 1;
    scanf(
"%d"&kase);
    
while (kase--) {
          scanf(
"%d %d %d %d %d"&a, &b, &c, &d, &k);
          
if (k == 0) {
             printf(
"Case %d: 0\n", o++);
             
continue;
          }
          
int x = b/k;
          
int y = d/k;
          
if (x == 0 || y == 0) {
             printf(
"Case %d: 0\n", o++);
             
continue;
          }
          
if (x > y) swap(x,y);
          
long long ans = 0;
          
for (i = 0; i < sum; i++) {
              
if (x < tb[i].v) break;
              
long long tmpx = x/tb[i].v;
              
long long tmpy = y/tb[i].v;
              
long long c = tmpx*tmpy-(tmpx-1)*tmpx/2;
              ans 
+= c*tb[i].k;
          }
          printf(
"Case %d: %I64d\n",o++,ans);
    }
    
return 0;    
}