题解
-
我们设a1表示a数组中最小的元素,dis[i]表示我通过使用若干个数,使得结果模a1=i,假设结果为x*a1+i,最小的x是多少
-
那么我们可以连边后求最短路来求出dis数组,最后统计答案即可
-
在做物品无限的背包问题时,可以把问题转换成对某个值取模后求最短路
- 新姿势get√
代码
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <queue> 5 #include <algorithm> 6 using namespace std; 7 #define ll long long 8 const int N=500010; 9 int n,cnt,head[N],a[20]; 10 ll l,r,ans,dis[N]; 11 bool vis[N]; 12 struct edge{int to,from;ll v;}e[N*12]; 13 queue<int>Q; 14 void insert(int x,int y,int v) { e[++cnt].to=y,e[cnt].from=head[x],e[cnt].v=v,head[x]=cnt; } 15 void spfa() 16 { 17 Q.push(0),vis[0]=1; 18 while (!Q.empty()) 19 { 20 int u=Q.front(); Q.pop(); 21 for (int i=head[u];i;i=e[i].from) 22 if (dis[u]+e[i].v<dis[e[i].to]) 23 { 24 dis[e[i].to]=dis[u]+e[i].v; 25 if (!vis[e[i].to]) vis[e[i].to]=1,Q.push(e[i].to); 26 } 27 vis[u]=0; 28 } 29 } 30 int main() 31 { 32 scanf("%d%lld%lld",&n,&l,&r); 33 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 34 sort(a+1,a+n+1),dis[0]=0; 35 for (int i=1;i<a[1];i++) dis[i]=(ll)1e12; 36 for (int i=2;i<=n;i++) for (int j=0;j<a[1];j++) insert(j,(j+a[i]%a[1])%a[1],a[i]/a[1]+(j+a[i]%a[1]>=a[1])); 37 spfa(),ans=0; 38 for (int i=0;i<a[1];i++) ans+=max((r-i-a[1]*max((ll)0,dis[i]-1))/a[1],(ll)0)-max((l-1-i-a[1]*max((ll)0,dis[i]-1))/a[1],(ll)0); 39 printf("%lld",ans); 40 }