题意:中文题意不解释...
思路:这道题居然可以转化为最短路orz,要等式有非负整数解,我们可以转化一下:每个ai不限数量,问你能用ai数组拼出多少个Bmin~Bmax范围内的数,有点像完全背包的感觉,看怎样组合能拼出范围内的数。
我们找出ai中不为零的最小数记为p,如果我们把每个数进行操作ai%p ,那么所有的ai我们都可以用整数倍的p加上它的取模表示了。我们用dis[i]表示如果有一个数x:x%p == i,那么dis储存最小的x,也就是说dis储存着我们能用ai数组拼出的取模p等于i的最小的数,那么dis+n*p我们也能拼出。然后问题就变成了求出dis[i]的最小值,用最短路解决。
代码:
#include<cstdio> #include<set> #include<vector> #include<cmath> #include<queue> #include<cstring> #include<algorithm> #define ll long long using namespace std; const int maxn = 500000+5; const int INF = 0x3f3f3f3f; bool vis[maxn]; ll dis[maxn]; int a[15]; int mod,n; void spfa(int start){ memset(vis,false,sizeof(vis)); memset(dis,INF,sizeof(dis)); vis[start] = true; dis[start] = 0; queue<int> q; while(!q.empty()) q.pop(); q.push(start); while(!q.empty()){ int u = q.front(); q.pop(); vis[u] = false; for(int i = 1;i <= n;i++){ int w = a[i]; int v = (u + w) % mod; if(dis[v] > dis[u] + w){ dis[v] = dis[u] + w; if(!vis[v]){ q.push(v); vis[v] = true; } } } } } ll query(ll x){ ll ans = 0; for(int i = 0;i < mod;i++){ if(dis[i] <= x) ans += (x - dis[i]) / mod + 1; //k*mod + dis == x } return ans; } int main(){ ll Bmx,Bmn; scanf("%d%lld%lld",&n,&Bmn,&Bmx); mod = INF; for(int i = 1;i <= n;i++){ scanf("%d",&a[i]); if(a[i] == 0){ i--,n--; //为0删除 } mod = min(mod,a[i]); } spfa(0); printf("%lld ",query(Bmx) - query(Bmn - 1)); return 0; }