2017.10.06【NOIP提高组】模拟赛B组 整除 题解

传送门

Description

给出n个数a1,a2……an,求区间[L,R]中有多少个整数不能被其中任何一个数整除。

Input

第一行三个正整数,n,L,R。
第二行n个正整数a1,a2……an

Output

一个数,即区间[L,R]中有多少个整数不能被其中任何一个数整除。

Sample Input

2 1 1000
10 15

Sample Output

867

Data Constraint

对于30%的数据,1<=n<=10,1<=L,R<=1000
对于100%的数据,1<=n<=18,1<=L,R<=10^9

Analysis

我们可以开一个数组Bi表示由i个元素构成的最小公倍数
对于只有一个元素A1时,则B1-1=A1;
当加入第二个元素A2时,则B2-1=lcm(B1-1,A2)=lcm(A1,A2),B1-2=A2;
当加入第三个元素A3时,则B3-1=lcm(B2-1,A3)=lcm(lcm(A1,A2),A3),B2-2=lcm(B1-1,A3)=lcm(A1,A3),B2-3=lcm(B1-2,A3)=lcm(A2,A3)
……以此类推
则每加入一个元素Ai
有:

for(j=i;j>=2;i--)
    for(k=1;k<=b[j-1][0];k++) b[j][++b[j][0]]=lcm(b[j-1][k],a[i]);

最后统计答案,注意奇加偶减

Realization

#include<bits/stdc++.h>
using namespace std;
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
#define fin(x) freopen(""#x".in","r",stdin)
#define fout(x) freopen(""#x".out","w",stdout)
#define open(x) fin(x);fout(x)
#define ll long long
#define inf INT_MAX

ll n,l,r,i,j,k,s,ss,a[19],b[19][100000];
ll gcd(ll a,ll b){
    if(b==0) return a;
    return gcd(b,a%b);
}
ll lcs(ll a,ll b){
    return a*b/gcd(a,b);
}
ll f(ll x){
    s=0;
    memset(b,0,sizeof(b));
    fo(i,1,n){
        s+=x/a[i];
        fd(j,i,2){
            ss=0;
            fo(k,1,b[j-1][0]){
                b[j][++b[j][0]]=lcs(b[j-1][k],a[i]);
                ss+=x/b[j][b[j][0]];
            }
            if(j%2==0) s-=ss;else s+=ss;
        }
        b[1][++b[1][0]]=a[i];
    }
    return s;
}
int main(){
    scanf("%lld%lld%lld",&n,&l,&r);
    fo(i,1,n) scanf("%lld",&a[i]);
    printf("%lld",(r-l+1)-(f(r)-f(l-1)));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值