bzoj 2118
2118: 墨墨的等式
Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 2390 Solved: 937
[Submit][Status][Discuss]
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
3 5
Sample Output
5
HINT
对于100%的数据,N≤12,0≤ai≤5*10^5,1≤BMin≤BMax≤10^12。
此题用最短路来解决背包问题,这类问题有以下特征:
物品数量无穷
物品体积不大
目标体积较大
这类问题通过转化为模域的存在性来求解。
不多说,附代码:
#include "iostream" #include "cstdio" #include "cstring" #include "cstdlib" #include "queue" #include "cctype" #include "algorithm" using namespace std; const int maxn = 500005; int n ,num[25] ,que[maxn+5] ,head ,minn ,tail; long long from ,to ,dis[maxn]; bool vis[maxn]; void read(int &x) { x = 0; char c = getchar(); while(!isdigit(c)) c = getchar(); while(isdigit(c)) { x = (x<<3) + (x<<1) + c - '0'; c = getchar(); } return ; } long long qry(long long x) { long long t = 0; for(int i=0; i<minn; i++) if(dis[i] <= x) t+=(x-dis[i])/minn+1; return t; } int main() { read(n); scanf("%lld%lld" ,&from ,&to); minn = 1e6; for(int i = 1; i <=n; i++) { read(num[i]); if(!num[i]) { i--; n--; continue; } minn = min(minn ,num[i]); } for(int i=1; i<minn; i++) dis[i] = to+1; que[++head] = 0; vis[0] = 1; while(tail != head) { tail =tail%maxn+1; int t = que[tail]; vis[t] = 0; for(int i=1; i<=n; i++) { int y = (num[i]+t)%minn; if(dis[t]+num[i] < dis[y]) { dis[y] = dis[t]+num[i]; if(!vis[y]) { head = head%maxn+1; que[head] = y; vis[y] = 1; } } } } long long ans = qry(to) - qry(from-1); printf("%lld\n" ,ans); return 0; }
河西,河东,穷少年