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;
}

 

posted @ 2018-09-20 12:07  zzuqy  阅读(165)  评论(0编辑  收藏  举报