/**//* 题意:求[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; }
|