您的位置:首页 > 其它

bzoj2118 墨墨的等式

2017-09-12 17:21 579 查看

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*10^5,1≤BMin≤BMax≤10^12。

正解:$spfa$。

其实这题思路并不难,但是很难想到啊。。

其实这是一个完全背包问题,然后求一个区间是否可以被选出来。

我们考虑一个式子:$ax+k$,其中$k<a$,$a$是任意一个物品的重量。

那么如果$ax+k$可以被表示出来,$a(x+1)+k$肯定也可以被表示出来,$a(x+p)+k$同理。

那么我们可以任选一个物品(直接选重量最小的就行了),假设它的重量为$m$,构造一个$[0,m-1]$这$m$个点的图。

然后$dis[i]$表示在$\ mod \ m$意义下为$i$的数中,实际能凑出的最小的数是什么,直接跑最短路即可。

最后枚举每一个点,算出它加上$xm$以后能凑出的$[minb,maxb]$中的数量,加起来就行了。

#include <bits/stdc++.h>
#define il inline
#define RG register
#define ll long long
#define N (500010)

using namespace std;

int vis
,a
,n,m;
ll dis
,ql,qr;

queue <int> Q;

il int gi(){
RG int x=0,q=1; RG char ch=getchar();
while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
if (ch=='-') q=-1,ch=getchar();
while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
return q*x;
}

il ll query(RG ll x){
RG ll res=0;
for (RG int i=0;i<m;++i){
if (dis[i]>x) continue;
res+=(x-dis[i])/m+1;
}
return res;
}

int main(){
#ifndef ONLINE_JUDGE
freopen("equal.in","r",stdin);
freopen("equal.out","w",stdout);
#endif
n=gi(),cin>>ql>>qr,m=1000000;
for (RG int i=1;i<=n;++i){
a[i]=gi(); if (!a[i]){ --n,--i; continue; }
m=min(m,a[i]);
}
for (RG int i=1;i<m;++i) dis[i]=qr+1; Q.push(0),vis[0]=1;
while (!Q.empty()){
RG int x=Q.front(),v; Q.pop();
for (RG int i=1;i<=n;++i){
v=(x+a[i])%m;
if (dis[v]>dis[x]+a[i]){
dis[v]=dis[x]+a[i];
if (!vis[v]) vis[v]=1,Q.push(v);
}
}
vis[x]=0;
}
printf("%lld\n",query(qr)-query(ql-1)); return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: