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


    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 ;
    }
    
  • 相关阅读:
    源代码的下载和翻译
    Git使用入门
    搭建Andriod开发环境
    Andriod系统移植与驱动开发概述
    直观打印二叉树
    深度优先遍历图(DFS)
    《UNIX网络编程 卷1 套接字联网API》(第三版)阅读笔记----2018.5.22
    C/C++
    实现具有getMin功能的栈
    用两个栈来模拟一个队列
  • 原文地址:https://www.cnblogs.com/beretty/p/9864532.html
Copyright © 2020-2023  润新知