您的位置:首页 > 其它

BZOJ2118: 墨墨的等式

2016-11-13 21:01 316 查看

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。

Source

直接枚举显然不显示 考虑在同余系下更高效的做法
如果凑出了一个B,那么B+Ai也能被凑出来
故我们只需找最小的B
转化成最短路 由x向x+Ai%min(Ai)连边
然后直接跑即可
#include<bits/stdc++.h>

using namespace std;

const long long inf=1000000000001;

const long long maxn=500050;

struct edge
{
long long to,nxt;
long long val;
}e[maxn<<4];

long long head[maxn];

long long cnt;

inline void addedge(long long x,long long y,long long w)
{
e[++cnt].to=y;
e[cnt].nxt=head[x];
head[x]=cnt;
e[cnt].val=w;
}

long long n;

long long a[maxn];

long long l,r;

long long dis[maxn];

bool vis[maxn];

inline void spfa()
{
queue <long long > q;
q.push(0);
vis[0]=1;
while(!q.empty())
{
long long x=q.front();
q.pop();
vis[x]=0;
for(long long i=head[x];i;i=e[i].nxt)
{
long long y=e[i].to;
if(dis[y]>dis[x]+e[i].val)
{
dis[y]=dis[x]+e[i].val;
if(!vis[y])
{
vis[y]=1;
q.push(y);
}
}
}
}
}

inline long long work(long long x,long long y,long long mod)
{
if(x<y) return 0;
return (x-y)/mod+1;
}

int main()
{
long long minn=inf;
scanf("%lld",&n);
scanf("%lld%lld",&l,&r);
for(long long i=1;i<=n;i++)
scanf("%lld",&a[i]),minn=min(a[i],minn);
for(long long i=1;i<=n;i++)
{
for(long long j=0;j<minn;j++)
{
addedge(j,(j+a[i])%minn,a[i]);
}
}
for(long long i=1;i<minn;i++)
dis[i]=inf;
spfa();
long long ans=0;
for(long long i=0;i<minn;i++)
ans+=work(r,dis[i],minn)-work(l-1,dis[i],minn);
printf("%lld",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: