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 }