bzoj 2118 墨墨的等式 - 图论最短路建模

墨墨突然对等式很感兴趣,他正在研究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。


  直接说正解,找到ai中的一个数(通常找最小的那一个,这样可以降低时间复杂度,至于为什么,看完应该就知道了),暂且设它为m吧。

  我们知道如果存在一个x,它能够被凑出来,那么(x + m), (x + 2m), ...都可以被凑出来。现在我们要找到这么一个最小的x。先建立一些点0,1,2,...,m - 1,表示满足条件的B模m的值。暂时先不考虑如何求出一次Bmin ~ Bmax中满足条件的B,因为可以用0到Bmax中的方案数减去0到Bmin - 1中的方案数。每个点连n - 1条边,第i个点的第j条边连向第(i + aj) % m个点,边权为aj

  看似有些跑题了,现在来讲讲它在题目中的含义。现在我们希望求到所有满足条件的最小的x,我们知道,当B模m的值为0时,B最小为0。同时我们可以用这个推出与它相邻的点代表的最小的B。再仔细想想,多推一下,这不是等价于求最短路吗?也就是说,从节点0出发,到达i的距离表示,最小的B模m的值为i的B的值。

  最后计算一下方案数(相信你会做)就好了。还有特殊处理当某个a等于0的时候,不然会整数被零除,然后无限RE。另外,贡献一发wa,建图注意是单向的,减个aj就不知道是不是满足了,笑。

Code

  1 /**
  2  * bzoj
  3  * Problem#2118
  4  * Accepted
  5  * Time:2888ms
  6  * Memory:93712k
  7  */
  8 #include<iostream>
  9 #include<fstream> 
 10 #include<sstream>
 11 #include<algorithm>
 12 #include<cstdio>
 13 #include<cstring>
 14 #include<cstdlib>
 15 #include<cctype>
 16 #include<cmath>
 17 #include<ctime>
 18 #include<map>
 19 #include<stack>
 20 #include<set>
 21 #include<queue>
 22 #include<vector>
 23 #ifndef WIN32
 24 #define AUTO "%lld"
 25 #else
 26 #define AUTO "%I64d"
 27 #endif
 28 using namespace std;
 29 typedef bool boolean;
 30 #define inf 0xfffffff
 31 #define smin(a, b) (a) = min((a), (b))
 32 #define smax(a, b) (a) = max((a), (b))
 33 template<typename T>
 34 inline boolean readInteger(T& u) {
 35     char x;
 36     int aFlag = 1;
 37     while(!isdigit((x = getchar())) && x != '-' && x != -1);
 38     if(x == -1)    {
 39         ungetc(x, stdin);
 40         return false;
 41     }
 42     if(x == '-') {
 43         aFlag = -1;
 44         x = getchar();
 45     }
 46     for(u = x - '0'; isdigit((x = getchar())); u = u * 10 + x - '0');
 47     u *= aFlag;
 48     ungetc(x, stdin);
 49     return true;
 50 }
 51 
 52 ///map template starts
 53 typedef class Edge{
 54     public:
 55         int end;
 56         int next;
 57         int w;
 58         Edge(const int end = 0, const int next = 0, const int w = 0):end(end), next(next), w(w) {    }
 59 }Edge;
 60 
 61 typedef class MapManager{
 62     public:
 63         int ce;
 64         int *h;
 65         Edge *edge;
 66         MapManager() {    }
 67         MapManager(int points, int limit):ce(0) {
 68             h = new int[(const int)(points + 1)];
 69             edge = new Edge[(const int)(limit + 1)];
 70             memset(h, 0, sizeof(int) * (points + 1));
 71         }
 72         inline void addEdge(int from, int end, int w) {
 73             edge[++ce] = Edge(end, h[from], w);
 74             h[from] = ce;
 75         }
 76         Edge& operator [] (int pos) {
 77             return edge[pos];
 78         }
 79 }MapManager;
 80 #define m_begin(g, i) (g).h[(i)]
 81 ///map template ends
 82 
 83 int n;
 84 long long bmin, bmax;
 85 MapManager g;
 86 int* a;
 87 int moder = inf;
 88 
 89 inline void init() {
 90     readInteger(n);
 91     readInteger(bmin);
 92     readInteger(bmax);
 93     a = new int[(const int)(n + 1)];
 94     for(int i = 1; i <= n; i++) {
 95         readInteger(a[i]);
 96         if(a[i] == 0) {
 97             i--, n--;
 98             continue;
 99         }
100         smin(moder, a[i]);
101     }
102 }
103 
104 boolean *visited;
105 long long* dis;
106 queue<int> que;
107 inline void spfa(int s) {
108     visited = new boolean[(const int)(moder)];
109     dis = new long long[(const int)(moder)];
110     memset(visited, false, sizeof(boolean) * (moder));
111     memset(dis, 0x7f, sizeof(long long) * (moder));
112     dis[s] = 0;
113     que.push(s);
114     while(!que.empty()) {
115         int e = que.front();
116         que.pop();
117         visited[e] = false;
118         for(int i = m_begin(g, e); i != 0; i = g[i].next) {
119             int &eu = g[i].end;
120             if(dis[e] + g[i].w < dis[eu]) {
121                 dis[eu] = dis[e] + g[i].w;
122                 if(!visited[eu]) {
123                     que.push(eu);
124                     visited[eu] = true;
125                 }
126             }
127         }
128     }
129 }
130 
131 inline long long calc(long long x) {
132     long long ret = 0;
133     for(int i = 0; i < moder; i++) {
134         if(dis[i] <= x)
135             ret += (x - dis[i]) / (long long)moder + 1;
136     }
137     return ret;
138 }
139 
140 inline void solve() {
141     g = MapManager(moder, moder * n * 2);
142     for(int i = 0; i < moder; i++) {
143         for(int j = 1; j <= n; j++) {
144             if(a[j] == moder) continue;
145             g.addEdge(i, (i + a[j]) % moder, a[j]);
146         }
147     }
148     spfa(0);
149     long long res = calc(bmax) - calc(bmin - 1);
150     printf(AUTO, res);
151 }
152 
153 int main() {
154     init();
155     solve();
156     return 0;
157 }

 

posted @ 2017-03-24 21:14  阿波罗2003  阅读(288)  评论(0编辑  收藏  举报