【[国集]墨墨的等式】同余类BFS
停课了orz,然而马上就NOIP了,我还这么弱,十分害怕。
BZOJ2118(非权)
Luogu2371
2118: 墨墨的等式
Time Limit: 10 Sec Memory Limit: 259 MB Submit: 2882 Solved: 1177 [Submit][Status][Discuss]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
这是一道数学?这是一个背包?不,这是一道图论! 观察发现系数都很小。我们根据POI2013SUMS的同余类bfs,首先转化为在同余最小的那个距离上搞,这样我们就可以找到第一个在%X(假定X是最小)最小的到达那个%X意义下的最小数。这样%X意义下更大的答案也一定可以到达。这样我们跑一下SPFA(显然这种题对SPFA十分友好),就可以找出来了,之后就随便搞出来了。 对于这样的一类题,有一个名字,叫同余类BFS,有机会学一学还是觉得十分机智的. talk is cheap , show me code!#include<iostream>
#include<algorithm>
#include<cstdio>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn = 500005;
ll dis[maxn];
int n;ll bmin,bmax;
int a[15]; bool rd[maxn];
queue<int>q;
void spfa() {
for(int i=0;i<a[1];i++) dis[i]=1e15;
q.push(0); rd[0]=1; dis[0]=0;
while(q.size()) {
int x=q.front(); q.pop(); rd[x]=0;
for(int i=2;i<=n;i++) {
int o = (x+a[i])%a[1];
if(dis[o]>dis[x]+a[i]) {
dis[o]=dis[x]+a[i];
if(!rd[o]) {
q.push(o); rd[o]=1;
}
}
}
}
}
int main() {
scanf("%d%lld%lld",&n,&bmin,&bmax);
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]);
}
sort(a+1,a+1+n);
spfa();
ll ans = 0;
for(int i=0;i<a[1];i++) {
if(dis[i]<=bmax) {
if(dis[i]>=bmin) ans += ((bmax-dis[i])/a[1]+1);
else {
ans+=(bmax-dis[i])/a[1]+1;
ans-=(bmin-dis[i]+a[1]-1)/a[1];
}
}
}
printf("%lld",ans);
}

浙公网安备 33010602011771号