[国家集训队]墨墨的等式

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 ;
}
posted @ 2018-10-28 09:02  beretty  阅读(193)  评论(0编辑  收藏  举报