传送门
解析:
这道题卡数组大小卡得我心力交瘁。。
思路:
从来没见过的做法,跑最短路求解背包问题
我也是看了别的dalao的题解才会的
我们选择最小的 a i a_i ai作为模数,使得其他所有数都可以由它转移过来。
怎么转移?
令
d
[
i
]
d[i]
d[i]表示当物体的总重
%a_i=q
时,物体最少的重量。设
d
[
i
]
=
t
d[i]=t
d[i]=t,那么显然对于所有的
x
x
x,如果
x
x%a_i=q
x且
x
>
=
t
x>=t
x>=t,都可以用总重最少的那个方案再加上若干个
p
p
p得到。
同时,考虑加入一个物体
u
u
u,那么显然有
d
[
(
i
+
u
)
d[(i+u)%a_i]
d[(i+u)可以由
d
[
i
]
+
u
d[i]+u
d[i]+u得到,这不就是两点间连边吗?
d
[
i
]
d[i]
d[i]求最小值不就是最短路吗?
然后这道题就解决了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
#define _debug(x) cerr<<#x<<" : "<<x<<endl
inline
ll getint(){
re ll num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
inline
void outint(ll a){
static char ch[23];
if(a==0)pc('0');
while(a)ch[++ch[0]]=a-a/10*10,a/=10;
while(ch[0])pc(ch[ch[0]--]^48);
}
cs int N=500005;
cs int M=7500005;
int last[N],nxt[M],to[M],ecnt;
ll w[M];
inline
void addedge(int u,int v,ll val){
nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v,w[ecnt]=val;
}
ll dist[N];
ll a[20];
int n;
ll maxn=2e18;
ll bl,br;
bool inq[N];
inline
ll query(ll x){
ll res=0;
for(int re i=0;i<maxn;++i)if(dist[i]<=x)res+=(x-dist[i])/maxn+1;
return res;
}
signed main(){
n=getint();
bl=getint();
br=getint();
for(int i=1;i<=n;++i){
a[i]=getint();
if(!a[i]){
--i;--n;
continue;
}
maxn=min(maxn,a[i]);
}
for(int re i=0;i<maxn;++i)
for(int re j=1;j<=n;++j)
addedge(i,(i+a[j])%maxn,a[j]);
queue<int> q;
memset(dist,0x3f,sizeof dist);
dist[0]=0;q.push(0);inq[0]=1;
while(!q.empty()){
int u=q.front();
q.pop();
inq[u]=0;
for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
if(dist[v]>dist[u]+w[e]){
dist[v]=dist[u]+w[e];
if(!inq[v])inq[v]=true,q.push(v);
}
}
}
outint(query(br)-query(bl-1));
return 0;
}