BZOJ2118:墨墨的等式(最短路)

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。

Solution 

看样子好像是一个很经典的题……

一开始读错题了难受了好久……后来发现题意可以化简成你有若干种价值为正的物品,每种无限个,问你给定区间$[B_{Min},B_{Max}]$中有多少个价值可以被凑出来。

设$Min=min(a_i)$,那么显然对于$val∈[0,Min-1]$,若价值$val$能被凑出来,那么$val+?*Min$也能被凑出来。

现在问题转化成了对于$val∈[0,Min-1]$,分别求最小可以被凑出来的$val+?*Min$。

这个问题就可以转化成最短路来求解了,对于每一个$val$,我们枚举$i$,然后添加一条边$val->(val+a_i)modMin$,边长为$a_i$,然后求解最短路就好了。

不懂的话画个图感性理解或者看看代码应该挺好用的

Code

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<queue>
 5 #define N (6000009)
 6 using namespace std;
 7 
 8 struct Edge{int to,next,len;}edge[N];
 9 struct Node
10 {
11     long long num,dis;
12     bool operator < (const Node a) const {return dis>a.dis;}
13 };
14 int n,a[N],head[N],num_edge,Min=1e9;
15 long long dis[N],Bmin,Bmax;
16 bool vis[N];
17 priority_queue<Node>q;
18 
19 void add(int u,int v,int l)
20 {
21     edge[++num_edge].to=v;
22     edge[num_edge].next=head[u];
23     edge[num_edge].len=l;
24     head[u]=num_edge;
25 }
26 
27 void Dijkstra(int s)
28 {
29     for (int i=0; i<Min; ++i) dis[i]=1e18;
30     dis[s]=0; q.push((Node){s,0});
31     while (!q.empty())
32     {
33         Node x=q.top(); q.pop();
34         if (vis[x.num]) continue;
35         vis[x.num]=true;
36         for (int i=head[x.num]; i; i=edge[i].next)
37             if (dis[x.num]+edge[i].len<dis[edge[i].to])
38             {
39                 dis[edge[i].to]=dis[x.num]+edge[i].len;
40                 q.push((Node){edge[i].to,dis[edge[i].to]});
41             }
42     }
43 }
44 
45 long long Calc(long long x)
46 {
47     long long ans=0;
48     for (int i=0; i<Min; ++i)
49         if (dis[i]<=x) ans+=(x-dis[i])/Min+1;
50     return ans;
51 }
52 
53 int main()
54 {
55     scanf("%d%lld%lld",&n,&Bmin,&Bmax);
56     for (int i=1; i<=n; ++i)
57     {
58         scanf("%d",&a[i]);
59         if (a[i]==0) {--i; --n; continue;}
60         Min=min(Min,a[i]);
61     }
62     if (!n) {puts("0"); return 0;}
63     for (int i=1; i<=n; ++i)
64         for (int j=0; j<Min; ++j)
65             add(j,(j+a[i])%Min,a[i]);
66     Dijkstra(0);
67     printf("%lld
",Calc(Bmax)-Calc(Bmin-1));
68 }
原文地址:https://www.cnblogs.com/refun/p/9606089.html