天天看点

bzoj 2118: 墨墨的等式 spfa

题目:

墨墨突然对等式很感兴趣,他正在研究\(a_1x_1+a_2y_2+ ... +a_nx_n=B\)存在非负整数解的条件,他要求你编写一个程序,给定\(N,\{a_n\}\)以及\(B\)的取值范围,求出有多少\(B\)可以使等式存在非负整数解。

题解:

首先我们发现 : 如果我们能够通过选取一些数凑到\(x\),那么我们肯定能够凑到$x + a_1 ,x + 2a_1 ,x + 3a_1, ... $

所以我们考虑在\(mod a_1\)的剩余系下进行操作.

记\(f[x]\)表示取到可以用\(k*a_1 + x\)表示的数的最小的\(k\)

这个dp我们可以直接利用最短路算法求解.

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(ll &x){
    x=0;char ch;bool flag = false;
    while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
    while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const ll maxn = 500500;
const ll lim = maxn<<1;
ll a[maxn],dis[maxn],q[lim + 10],l,r,n;
bool inq[maxn];
void spfa(){
    memset(dis,0x3f,sizeof dis);
    l = 0;r = -1;
    dis[0] = 0;q[++r] = 0;
    inq[0] = true;
    while(l <= r){
        ll u = q[l++];
        for(ll i=2;i<=n;++i){
            ll v = (u + a[i]) % a[1];
            if( dis[v] > dis[u] + (u+a[i])/a[1]){
                dis[v] = dis[u] + (u+a[i])/a[1];
                if(!inq[v]){
                    q[++r] = v;
                    inq[v] = true;
                }
            }
        }inq[u] = false;
    }
}
inline ll calc(ll x){
    ll ret = 0;
    for(ll i=0;i<a[1];++i){
        ret += max((x/a[1] + ((x % a[1]) >= i)) - dis[i],0LL);
    }return ret;
}
int main(){
    ll L,R;read(n);read(L);read(R);
    ll pos = 0;
    for(ll i=1;i<=n;++i){
        read(a[i]);
        if(pos == 0 || a[pos] > a[i]) pos = i;
    }swap(a[pos],a[1]);
    if(a[1] == 0) return puts("0");
    spfa();
    printf("%lld\n",calc(R) - calc(L-1));
    getchar();getchar();
    return 0;
}
           

转载于:https://www.cnblogs.com/Skyminer/p/6584462.html