BZOJ_2118_墨墨的等式_最短路

BZOJ_2118_墨墨的等式_最短路

Description

墨墨突然对等式很感兴趣,他正在研究a1x1+a2y2+…+anxn=B存在非负整数解的条件,他要求你编写一个程序,给定N、{an}、以及B的取值范围,求出有多少B可以使等式存在非负整数解。

Input

输入的第一行包含3个正整数,分别表示N、BMin、BMax分别表示数列的长度、B的下界、B的上界。输入的第二行包含N个整数,即数列{an}的值。

Output

输出一个整数,表示有多少b可以使等式存在非负整数解。

Sample Input

2 5 10
3 5

Sample Output

5

HINT

对于100%的数据,N≤12,0≤ai≤5*10^5,1≤BMin≤BMax≤10^12。


首先将L,R差分,求[1,x]有多少符合条件的数。

但是x太大,考虑将x%min{ai},这样我们求的x就变成500000以内的了。

设dis[i]表示长度为b且b%mina=i且最小的b。

也就是我们对于每个模之后的数求一个最小能表示的,然后就能求出有多少个可以表示的了。

代码:

#include <cstdio>
#include <string.h>
#include <algorithm>
#include <ext/pb_ds/priority_queue.hpp>
using namespace std;
using namespace __gnu_pbds;
#define N 500050
typedef long long ll;
ll dis[N],L,R;
int n,minl,a[20],vis[N];
__gnu_pbds::priority_queue<pair<ll,int> >q;
ll solve(ll x) {
    ll re=0;
    int i;
    for(i=0;i<minl;i++) {
        if(dis[i]<=x) {
            re+=(x-dis[i])/minl+1;
        }
    }
    return re;
}
int main() {
    scanf("%d%lld%lld",&n,&L,&R);
    int i;
    minl=1<<30;
    for(i=1;i<=n;i++) {
        scanf("%d",&a[i]);
        minl=min(minl,a[i]);
    }
    memset(dis,0x3f,sizeof(dis));
    dis[0]=0; q.push(make_pair(0,0));
    while(!q.empty()) {
        int x=q.top().second; q.pop();
        if(vis[x]) continue;
        vis[x]=1;
        ll v=dis[x];
        for(i=1;i<=n;i++) {
            if(dis[(v+a[i])%minl]>v+a[i]) {
                dis[(v+a[i])%minl]=v+a[i];
                q.push(make_pair(-dis[(v+a[i])%minl],(v+a[i])%minl));
            }
        }
    }
    printf("%lld\n",solve(R)-solve(L-1));
}

猜你喜欢

转载自www.cnblogs.com/suika/p/9128015.html