zoj2836就是裸的求lcm进行容斥,用dfs比较直观
zoj3233增加了一个集合b,lcm(b)的倍数是不符合条件的
那么在zoj2836的基础上,把lcm(x,lcm(b))造成的影响减去即可
用状态压缩来枚举集合状况
/* 给定两个集合s1,s2 求区间[L,R]能被s1里至少一个数整除,且不能被s2里至少一个数整除的个数 lcm(s2)的所有倍数都不可行,所以当dfs遇到lcm==lcm(s2)时要反过来 要防止越界的情况 */ #include<bits/stdc++.h> using namespace std; #define ll long long const ll INF=1e18+100; ll LCM,L,R,n,m,a[30],b[1000]; ll __lcm(ll a,ll b){//防溢出lcm if(a==-1 || b==-1)return -1; ll d=__gcd(a,b); if(INF/b < a/d)return -1;//lcm越界了 return a/__gcd(a,b)*b;//顺序不能错 } ll query(ll x){//状态压缩集合解法 ll res=0; for(ll i=1;i<(1<<n);i++){//枚举每种状态集 ll num=1,cnt=0; for(ll j=0;j<n;j++) if(i & ((ll)1<<j)) cnt++,num=__lcm(num,a[j+1]);//下标j偏移了一位 if(num==-1)num=INF; ll tmp=__lcm(num,LCM); if(tmp==-1)tmp=INF; if(cnt%2)res+=x/num-x/tmp; else res-=x/num-x/tmp; } return res; } int main(){ while(cin>>n>>m>>L>>R,n){ for(int i=1;i<=n;i++)cin>>a[i]; for(int i=1;i<=m;i++)cin>>b[i]; LCM=1; for(int i=1;i<=m;i++)LCM=__lcm(LCM,b[i]); cout<<query(R)-query(L-1)<<endl; } }