• Atcoder Beginner Contest 164 E Two Currencies(拆点+最短路)


    题目链接

    题意:有 (n) 个城市,它们由 (m) 条双向道路连接,保证它们能够彼此到达。第 (i) 条道路连接 (u_i,v_i),需要花费 (x_i) 个银币,耗费 (t_i) 秒的时间。每个城市处都有兑换银币处,第 (i) 个城市中你可以用 (1) 个金币兑换 (c_i) 个银币,可以兑换无限次,不过兑换 (1) 次需要花费 (d_i) 秒的时间。你一开始在 (1) 号城市,有 (s) 个银币和无限多的金币,求到其它城市需要耗费的最小时间。
    (1 leq n leq 50)(1 leq x_i leq 50)(1 leq t_i,d_i leq 10^9)(1 leq s,c_i leq 10^9)

    abc 的 F 都切不掉,只好水 E 的题解了
    观察到虽然 (s,c_i) 很大,但是 (x_i) 只有 (50)。这也就意味着到其它需要花费的银币绝对不会超过 (49 imes 50=2450),所以如果当前银币数超过 (2450),就可以将它看作 (2450)
    我们将“当前位于城市 (i),手中有 (j) 个银币”看成一个点 ((i,j)),那么我们可以重新建一张图,两个状态 ((x_1,y_1),(x_2,y_2)) 之间有一条有向边当且仅当 ((x_1,y_1)) 可以到达 ((x_2,y_2)),边权为花费的时间。
    建图:

    • ((i,j) ightarrow (i,j+c_i)),边权为 (d_i)
    • ((i,j) ightarrow (k,j-x_p)),边权为 (t_p),其中 ((i,k)) 之间有边,编号为 (p)(j geq x_p)
      跑一遍 dijkstra,起点为 ((1,s)),点 (u) 的答案就是 (min (1,s))((u,i)) 的距离。
      大概是网络流基本建图模型?(雾
    #include <bits/stdc++.h>
    using namespace std;
    #define fi			first
    #define se			second
    #define fz(i,a,b)	for(int i=a;i<=b;i++)
    #define fd(i,a,b)	for(int i=a;i>=b;i--)
    #define foreach(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
    #define all(a)		a.begin(),a.end()
    #define giveup(...) return printf(__VA_ARGS__),0;
    #define fill0(a)	memset(a,0,sizeof(a))
    #define fill1(a)	memset(a,-1,sizeof(a))
    #define fillbig(a)	memset(a,0x3f,sizeof(a))
    #define fillsmall(a) memset(a,0xcf,sizeof(a))
    #define mask(a)		(1ll<<(a))
    #define maskx(a,x)	((a)<<(x))
    #define _bit(a,x)	(((a)>>(x))&1)
    #define _sz(a)		((int)(a).size())
    #define filei(a)	freopen(a,"r",stdin);
    #define fileo(a)	freopen(a,"w",stdout);
    #define fileio(a) 	freopen(a".in","r",stdin);freopen(a".out","w",stdout)
    #define eprintf(...) fprintf(stderr,__VA_ARGS__)
    #define put(x)		putchar(x)
    #define eoln        put('
    ')
    #define space		put(' ')
    #define y1			y_chenxiaoyan_1
    #define y0			y_chenxiaoyan_0
    #define int long long
    typedef pair<int,int> pii;
    inline int read(){
    	int x=0,neg=1;char c=getchar();
    	while(!isdigit(c)){
    		if(c=='-')	neg=-1;
    		c=getchar();
    	}
    	while(isdigit(c))	x=x*10+c-'0',c=getchar();
    	return x*neg;
    }
    inline void print(int x){
    	if(x<0){
    		putchar('-');
    		print(abs(x));
    		return;
    	}
    	if(x<=9)	putchar(x+'0');
    	else{
    		print(x/10);
    		putchar(x%10+'0');
    	}
    }
    inline int qpow(int x,int e,int _MOD){
    	int ans=1;
    	while(e){
    		if(e&1)	ans=ans*x%_MOD;
    		x=x*x%_MOD;
    		e>>=1;
    	}
    	return ans;
    }
    int n=read(),m=read(),s=read(),c[55],d[55];
    struct edge{
    	int u,v,w;
    	edge(){/*ycxakioi*/}
    	edge(int _u,int _v,int _w){
    		u=_u;v=_v;w=_w;
    	}
    };
    const int MAGIC=2456;
    inline int id(int x,int y){
    	return x*(MAGIC+1)+y;
    }
    vector<edge> g[55*2555];
    int dist[55*2555],vis[25*2555];
    priority_queue<pii,vector<pii>,greater<pii> > q;
    signed main(){
    	fz(i,1,m){
    		int u,v,a,b;cin>>u>>v>>a>>b;
    		fz(j,0,MAGIC){
    			if(j>=a){
    				g[id(u,j)].push_back(edge(id(u,j),id(v,j-a),b));
    				g[id(v,j)].push_back(edge(id(v,j),id(u,j-a),b));
    			}
    		}
    	}
    	fz(i,1,n)	c[i]=read(),d[i]=read();
    	fz(i,1,n){
    		fz(j,0,MAGIC-1){
    			int cur=j+c[i];
    			if(cur>=MAGIC){
    				g[id(i,j)].push_back(edge(id(i,j),id(i,MAGIC),d[i]));
    			}
    			else{
    				g[id(i,j)].push_back(edge(id(i,j),id(i,cur),d[i]));
    			}
    		}
    	}
    	fillbig(dist);
    	dist[id(1,min(s,MAGIC))]=0;
    	q.push({0,id(1,min(s,MAGIC))});
    	while(!q.empty()){
    		pii p=q.top();q.pop();
    		int sum=p.fi,x=p.se;
    		if(sum>dist[x])	continue;
    		foreach(it,g[x]){
    			int y=it->v,z=it->w;
    			if(dist[y]>dist[x]+z){
    				dist[y]=dist[x]+z;
    				q.push({dist[y],y});
    			}
    		}
    	}
    	fz(i,2,n){
    		int mn=0x3f3f3f3f3f3f3f3fll;
    		fz(j,0,MAGIC)	mn=min(mn,dist[id(i,j)]);
    		cout<<mn<<endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    chrony时间同步工具
    SyntaxError: missing ; before statement
    SQL 获得两个时间段之间的数据
    EasyUI DataGrid 获得分页信息
    c#里如何实现讲一个字符串数组例如 “112,221”转化成两个字符串数组“112” “221” 中间以逗号隔开
    SQL 将一个表中的所有记录插入到一个临时表中
    SQL查找指定行的记录
    SQL 中的Begin...End语句
    SQL将完整时间字段截取到年月日
    Linux学习之三:档案与文件系统的压缩与打包
  • 原文地址:https://www.cnblogs.com/ET2006/p/12811034.html
Copyright © 2020-2023  润新知