 /**//*
題意:求[low,high]內有多少個數,這些數至少能整除一個A[]里面的數
同時,不能整除任何一個B[]里面的數
na<=15 nb<=500
"if it's divisible by at least one number from BLN and not divisible by at least one number from BUN. "
陰人了,"not divisible by at least one"一個都不能整除
用容斥
答案就是|A-B| = |A| - |AB| 即 所有能整除A至少一個的數 - 這些數中能整除所有B中的數

能整除所有B的數即整除B中所有數的LCM

對于|A|,|AB|(能整除A,整除AB的總數)用容斥做就行了

watashi的神奇容斥寫法 Orz
*/
#include<cstdio>
#include<cstring>
#include<assert.h>

const int MAXN = 18;

long long low,high;
long long A[MAXN] , AB[MAXN] , B;

 inline long long labs(long long a) {return a<0?-a:a;}

long long gcd(long long a,long long b)
  {
return b?gcd(b,a%b):a;
}

long long lcm(long long a,long long b)
  {
long long g = gcd(a,b);
//這里會超long long 用double判斷下!!
if((double)a/g*b > high )return high+1;
return a/g*b;//注意這里要先/g,否則a*b可能會溢出!
}

long long cal(long long A[],int n,long long x,long long y)//用遞歸的可能更快,而且好寫
  {
if(n==0)return y / x;
return cal(A,n-1,x,y) + cal(A , n-1 , (x>0?-1:1)*lcm(labs(x),A[n-1]) , y);
}

long long cal(int n,long long y)
  {
return (y-cal(A,n,1,y)) - (y-cal(AB,n,1,y));
}

int main()
  {
#ifdef ONLINE_JUDGE
#else
freopen("in","r",stdin);
#endif

int na,nb,x;
while( scanf("%d%d%lld%lld" , &na,&nb,&low,&high) , na )
 {
for(int i = 0; i<na ; i++)
 {
scanf("%lld",&A[i]);
}
B = 1;
for(int i = 0;i<nb;i++)
 {
scanf("%d",&x);
B = lcm(B,x);
}
for(int i = 0; i<na ; i++)
 {
AB[i] = lcm(A[i] , B);
}
printf("%lld\n",cal(na,high) - cal(na,low-1));
}
return 0;
}
|