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
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\n",Calc(Bmax)-Calc(Bmin-1)); 68 }