p1813
数论还是恐怖啊.
本题用了两次容斥和多次gcd的应用.
题目要求[x,y]中被8整除且不被a[i]整除的数.枚举[x,y]就gg了,临时处理边界也很麻烦,不如用一次容斥原理:ans[x,y]=ans[1,y]-ans[1,x-1];
那么求ans[1,y]怎么弄呢.
假如现在n=0,答案就是y/8;因为每隔八个数就有一个满足要求.
n=1时,在这么多满足要求的数中每8*a[1]/gcd(8,a[1])个数会有一个被a[i]整除了(在1-y中),要把它减去.
n=2时,我们要减去两次8*a[i]/gcd(8,a[i]),但是每8*a[1]*a[2]/gcd(8,a[1])/gcd(8,a[2])(在1-y中)的数被减了两次,我们还要把它加上去.
.........
能不能看出来容斥了呢?
那么写一个类似二进制的东西模拟,本题可A.
using namespace std; int n,m,ans,a[100],x,y,total; bool f[100]; int gcd(long long x,long long y) { if(y==0)return (x); else return(gcd(y,x%y)); } void work(int k,int x) { if(k>n) { long long num=8;int total=0; for(int i=1;i<=n;i++) if(f[i]) { num*=a[i]/gcd(num,a[i]); if(num>x)break; total++; } if(total%2==1)ans-=x/num; else ans+=x/num; return ; } f[k]=0; work(k+1,x); f[k]=1; work(k+1,x); } int main() { ios::sync_with_stdio(false); //freopen("123.in","r",stdin); //freopen("123.out","w",stdout); cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; cin>>x>>y; int a1,a2; work(1,x-1); a1=ans; ans=0; work(1,y); a2=ans; cout<<a2-a1; }