[国家集训队]墨墨的等式
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*105,1≤BMin≤BMax≤1012。
题解
可以用完全背包做
复杂度\(O(nm)\)
显然过不了
但是我们发现\(Vmax\)很小
所以可以用类似于同余的思想来做
可以找一个权值最小的点v
如果tot可以被凑出来,那么\(tot+k*v(k∈Z)\)都可以被凑出来
这样问题就可以变成了最短路了
这样我们就可以建图了
以权值为点
对于每一个点,都枚举点\(0 ~ v-1\),然后由\(v_i\)向\((v_i + a[i])\)连一条权值为\(a[i]\)的边
然后直接跑最短路求出能凑出\(0 ~ v-1\)的最小值就可以暴力算了
代码
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
# define LL long long
const int N = 15 ;
const int M = 500005 ;
using namespace std ;
int val[N] , upp ;
int hea[M] , num , n ;
LL Bmax , Bmin , dis[M] ;
bool vis[M] ;
struct Node { int id ; LL dis ; };
struct E {
int Nxt , to , dis ;
} edge[M << 3] ;
priority_queue < Node > q ;
inline bool operator < (Node a , Node b) { return a.dis > b.dis ; }
inline void add_edge(int from , int to , int dis) {
edge[++num].Nxt = hea[from] ;
edge[num].to = to ;
edge[num].dis = dis ;
hea[from] = num ;
}
inline void Dijkstra() {
memset(vis , false , sizeof(vis)) ;
memset(dis , 63 , sizeof(dis)) ;
dis[0] = 0LL ; q.push((Node){ 0 , 0 }) ;
while(!q.empty()) {
int u = q.top().id ; q.pop() ;
if(vis[u]) continue ; vis[u] = true ;
for(int i = hea[u] ; i ; i = edge[i].Nxt) {
int v = edge[i].to ;
if(dis[v] > dis[u] + edge[i].dis) {
dis[v] = dis[u] + edge[i].dis ;
if(vis[v]) continue ;
q.push((Node) { v , dis[v] }) ;
}
}
}
}
inline LL Solve(LL x) {
LL Ans = 0 ;
for(int i = 0 ; i < upp ; i ++)
if(dis[i] <= x)
Ans += (x - dis[i]) / upp + 1 ;
return Ans ;
}
int main() {
cin >> n >> Bmin >> Bmax ;
for(int i = 1 ; i <= n ; i ++) {
cin >> val[i] ;
if(!val[i]) -- n , -- i ;
}
sort(val + 1 , val + n + 1) ;
upp = val[1] ;
for(int i = 0 ; i < upp ; i ++)
for(int j = 1 , x ; j <= n ; j ++) {
x = (i + val[j]) % upp ;
add_edge(i , x , val[j]) ;
}
Dijkstra() ;
cout << Solve(Bmax) - Solve(Bmin - 1) << endl ;
return 0 ;
}