BZOJ 2118: 墨墨的等式(最短路dijkstra+堆)
2118: 墨墨的等式
Time Limit: 10 Sec
Memory Limit: 259 MBDescription###
墨墨突然对等式很感兴趣,他正在研究a1x1+a2y2+…+anxn=B存在非负整数解的条件,他要求>你编写一个程序,给定N、{an}、以及B的取值范围,求出有多少B可以使等式存在非负整数解。
Input###
输入的第一行包含3个正整数,分别表示N、BMin、BMax分别表示数列的长度、B的下界、B的上界。
输入的第二行包含N个整数,即数列{an}的值。
Output###
输出一个整数,表示有多少b可以使等式存在非负整数解。
Sample Input 1###
2 5 10
3 5
Sample Output 1###
5
HINT###
对于100%的数据,N≤12,0≤ai≤5*105,1≤BMin≤BMax≤1012。
题目地址: BZOJ 2118: 墨墨的等式
题解:
每个数都能表示成\(k*a[1]+x(0<=x<a[1])\)的形式
如果对于每个\(x\)我们求出最小的\(k*a[1]+x\)
那么把\([l,r]\)分成\([1,l-1]\)和\([1,r]\)来做,就可以轻松统计答案
问题就变成了如何求出最小的\(k*a[1]+x\)
把每个\(x\)都当做一个点
只需在\(x\)和\((x+a[j])\) mod \(a[1]\)之间连一条边权为\(a[j]\)的边,再跑一遍最短路即可
www.cnblogs.com/AGFghy/
AC代码
#include<cstdio>
#include<algorithm>
#include<queue>
#define pa pair<ll,int>
using namespace std;
typedef long long ll;
int n,num,now;
int len[6000005],point[6000005],next[6000005],p[500005],head[500005],a[20];
ll d[500005];
ll l,r,nl,nr;
void insert(int u,int v,int l)
{
num++; len[num]=l; point[num]=v; next[num]=head[u]; head[u]=num;
}
void Dijkstra(int x)
{
priority_queue<pa,vector<pa>,greater<pa> >q;
for (int i=0; i<=a[now]-1; i++)
d[i]=(ll)1e60,p[i]=0;
d[x]=0; q.push(make_pair(0,x));
while (!q.empty())
{
int now=q.top().second;
p[now]=1;
q.pop();
for (int i=head[now]; i; i=next[i])
{
int v=point[i];
if (p[v]) continue;
if (d[now]+len[i]<d[v])
{
d[v]=d[now]+len[i];
q.push(make_pair(d[v],v));
}
}
}
}
int main()
{
scanf("%d%lld%lld",&n,&l,&r);
l--;
for (int i=1; i<=n; i++)
scanf("%d",&a[i]);
sort(a+1,a+n+1);
now=1;
while (a[now]==0) now++;
for (int i=0; i<=a[now]-1; i++)
for (int j=2; j<=n; j++)
insert(i,(i+a[j])%a[now],a[j]);
Dijkstra(0);
for (int i=0; i<=a[now]-1; i++)
if (d[i]<=r)
{
if (l-d[i]>=0) nl+=((l-d[i])/a[now])+1;
if (r-d[i]>=0) nr+=((r-d[i])/a[now])+1;
}
printf("%lld\n",nr-nl);
}