BZOJ2118 由数论推导至图论!最短路SPFA
2017-03-24 13:52
399 查看
世界真的很大
今天上午pty大神讲图论,在应用章节莫名其妙地抛出了这道神题,题目是这样的:给出一个不定方程:a1*x1+a2*x2+a3*x3+……..+an*xn=B,这里a都是常数,x是未知数,求在给定区间l,r内,使得所有x都为非负整数的,满足条件的B的个数。
这道怎么看都是数论题的题,其实可以用图论来解决,我反正死活没想出来。。先来分析一下吧,我们在这些a里任取一个ai,表示为k,那么这个B%k肯定是在0–k-1之间的,如果一个B满足条件,这个B%k=d,那么(B+k)%k也肯定为d,那其实就是说,只要我们能找到,%k=d的,且满足条件的最小的B,在一直往上加k,直到加到r为止,能有多少个B,(这些B都是符合条件的),就得到了B%k=d所有的可能,在枚举不同的d,累加起来,不就是0–r内全部可能的B值了嘛。同理,0–l-1内所有可能的B值也可以求出,一减不就是l–r内的可能,不就是答案呐!
然后,为了使不同的余数d种类尽量少,所以k尽量小就可以了,取a里面的最小值即可,代码:
for(int i=1;i<=n;i++) { scanf("%d",&a[i]); if(a[i] == 0) { i--,n--; continue ; } small=min(small,a[i]); }
这里的small就是上文的k,还有就是如果哪一个a是0,就相当于没有这一项,就不用保存,当然small是不能为0的;
然后,之所以可以用spfa,就是因为要求余d时最小的B,用dis[d]保存,首先队首是0,因为余0时,B为0是肯定可以且最小的(非负),所以dis[0]=0,通过加上不同的a,得到新的余数,如果得到相同的余数的话,可以用B较小的来更新did值,或者说“松弛”,怎么样,spfa吧?代码:
void spfa() { queue<int> state; state.push(0); vis[0]=1; dis[0]=0; while(!state.empty()) { int u=state.front(); state.pop(); vis[u]=0; for(int i=1;i<=n;i++) { int y=(u+a[i])%small; if(dis[y]>dis[u]+a[i]) { dis[y]=dis[u]+a[i]; if(!vis[y]) { state.push(y); vis[y]=1; } } } } }
看起来不错,因为是用的stl里的queue,所以不用担心循环队列的问题。
好,上完整代码了:
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long dnt;
int vis[500010],n,a[500010],small;
dnt dis[500010],l,r,inf=1e9;
void spfa() { queue<int> state; state.push(0); vis[0]=1; dis[0]=0; while(!state.empty()) { int u=state.front(); state.pop(); vis[u]=0; for(int i=1;i<=n;i++) { int y=(u+a[i])%small; if(dis[y]>dis[u]+a[i]) { dis[y]=dis[u]+a[i]; if(!vis[y]) { state.push(y); vis[y]=1; } } } } }
dnt query(dnt k)
{
dnt ans=0;
for(int i=0;i<small;i++)
if(dis[i]<=k) ans+=(k-dis[i])/small+1;
return ans;
}
int main()
{
small=(1<<30)-1;
scanf("%d%lld%lld",&n,&l,&r);
for(int i=1;i<=n;i++) { scanf("%d",&a[i]); if(a[i] == 0) { i--,n--; continue ; } small=min(small,a[i]); }
for(int i=0;i<small;i++)
dis[i]=100000000000000000LL;
spfa();
printf("%lld",query(r)-query(l-1));
return 0;
}
嗯,就是这样;
相关文章推荐
- 题解BZOJ-2118 图论 SPFA + SLE 最短路 数论
- BZOJ 2118 数论+最短路(SPFA) 解题报告
- [bzoj2118] 图论SPFA
- bzoj 2118 墨墨的等式 - 图论最短路建模
- BZOJ2118墨墨的等式[数论 最短路建模]
- [图论训练]BZOJ 2118: 墨墨的等式 【最短路】
- (最短路) bzoj 2118
- ACM一类方程问题的求解[最短路建模] bzoj2118
- BZOJ-1975 魔法猪学院 K短路 (A*+SPFA)
- 【BZOJ 2118】 2118: 墨墨的等式 (最短路)
- 数论+spfa算法 bzoj 2118 墨墨的等式
- HDU6166 Senior Pan 解题报告【图论】【SPFA最短路】【随机】
- BZOJ1715 SPFA 浅谈图论之负环的多重化判定
- 图论浅析--最短路之SPFA
- 图论浅析--最短路之SPFA
- 洛谷P1144-最短路计算【日常最短路,日常图论,SPFA】
- BZOJ 1003 物流运输 (动态规划 SPFA 最短路)
- bzoj2154: Crash的数字表格/2693: jzptab [莫比乌斯反演、数论推导]
- 洛谷P1346-电车【日常图论,最短路,SPFA】
- BZOJ 1003 物流运输【dp+最短路SPFA】好题!