您的位置:首页 > 其它

【BZOJ2118】墨墨的等式(dijkstra)

2017-10-12 07:11 639 查看
墨墨的等式传送门

这道题很神奇。

找余数

如果 x 可以为负数,那就变成了拓展欧几里得,但 x 是非负整数,解决方法就不一样了。我们找到所有 a 中最小的非负 a,记做 mn。如果能凑成 mn*x+k (k<a),那么就能凑成 mn*(x+1)+k,也就是可以凑成 B~mn*x+k 之间所有与 mn*x+k 相差 mn 的数,所以我们就要找到对于每一个 k ( 1 <= k < mn ),最小的 mn*x+k 是多少。

dijkstra

记 dis[k] 为最小的 mn*x+k,我们发现如果 mn* x+k_1+a_i = mn*y+k_2 ,那么我们就可以用 dis[k_1] 更新 dis[k_2],即设 t = (k+a_i)%mn, f[t]=min( f[t], f[k]+a_i ),这很像求最短路,因此我们抽象地建一个图,跑 dijkstra。这是在用形象的图论解决抽象的数学问题,非常强。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;

typedef long long LL;
const int N=15, M=6000000, A=500010, INF1=1000000000;
const LL INF2=1000000000000000;
int n, mi, mn;
LL Bmn, Bmx;
LL dis[A];
int head[A], a
;
bool vis
;

struct Edge{
int to,next,w;
}e[M<<1];

inline void add(int u,int v,int w){
e[++mi] = (Edge){v,head[u],w};
head[u] = mi;
}

struct HeadNode{
LL w; int u;
bool operator < (const HeadNode & rhs) const{
return w>rhs.w;
}
};

priority_queue <HeadNode> Q;

inline void dijkstra(){
for(int i=1; i<mn; ++i) dis[i]=INF2;
Q.push((HeadNode){0,0}); dis[0]=0;
int u, v, p;
while(!Q.empty()){
HeadNode c = Q.top(); Q.pop();
u = c.u;
if(c.w!=dis[u]) continue;
for(p=head[u]; p; p=e[p].next){
v = e[p].to;
if(dis[v]>dis[u]+e[p].w){
dis[v] = dis[u]+e[p].w;
Q.push((HeadNode){dis[v],v});
}
}
}
}

inline LL query(LL x){
LL ans=0;
for(int i=0; i<mn; ++i) if(dis[i]<=x){
ans += (x-dis[i])/mn+1;
}
return ans;
}

int main(){
mn = INF1;
scanf("%d%lld%lld",&n,&Bmn,&Bmx);
for(int i=1; i<=n; ++i){
scanf("%d",&a[i]);
if(!a[i]){ n--; i--; continue; }
mn = min(mn,a[i]);			// 找最小的 a
}
for(int i=1; i<=n; ++i) if(a[i]%mn) vis[i]=true;
for(int i=0, j; i<mn; ++i){
for(j=1; j<=n; ++j) if(vis[j]){
add(i,(i+a[j])%mn,a[j]);	// 建图
}
}
dijkstra();
printf("%lld\n",query(Bmx)-query(Bmn-1));
while(1);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dijkstra