zoukankan      html  css  js  c++  java
  • [洛谷 3403] 跳楼机(同余最短路)

    题目

    题目地址

    题解

    当出现形如“给定 (n) 个整数,求这 (n) 个整数能拼凑出多少的其他整数((n) 个整数可以重复取)”,以及“给定 (n) 个整数,求这 (n) 个整数不能拼凑出的最小(最大)的整数”的问题时可以使用同余最短路的方法。

    引自 OI-wiki。

    不妨设 (x < y < z)。(为了减少状态)

    (dist[i]) 为最小的 (p=ay+bz)(p equiv i pmod {x})

    则可以对于每个 (i),连一条 (i->(i+y)\%x) 的边,边权为 (y),连一条 (i->(i+z)\%x) 的的边,边权为 (z)。在以 (1) 为起点这个图上跑最短路,就可以求出 (dist[i]) 了。

    注意 (x,y,z le 10^5),所以 (x)(y) 的最小公倍数最大是 (xy le 10^{10}) 不会爆 long long ,也就是说 (dist[i]) (如果不为 (INF) 的话)不会超过 (10^{10})

    求出 (dist[i]) 后,可以发现 (dist[i]+kx,k in Z) 都可以到达(这就是设计同余状态的意义),于是就可以算出可以到多少个楼层了。

    时间复杂度 (O(n log n))

    代码

    #include<bits/stdc++.h>
    #define int long long
    #define mp make_pair
    #define fi first
    #define se second
    using namespace std;
    inline int read() {
        int x = 0, f = 1; char ch = getchar();
        while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
        return x * f;
    }
    typedef pair<int,int> PII;
    const int N = 1e5+7;
    int h,x,y,z,cnt;
    int head[N],dist[N];
    struct Edge {
    	int next,to,w;
    }edge[N<<1];
    inline void add(int u,int v,int w) {
    	edge[++cnt] = (Edge)<%head[u],v,w%>;
    	head[u] = cnt;
    }
    bool vis[N];
    void Dijkstra() {
    	memset(dist, -1, sizeof(dist));
    	priority_queue<PII> q;
    	dist[1] = 1;
    	q.push(mp(-dist[1],1));
    	while(!q.empty()) {
    		int u = q.top().se;
    		q.pop();
    		if(vis[u]) continue;
    		vis[u] = 1;
    		for(int i=head[u];i;i=edge[i].next) {
    			int v = edge[i].to, w = edge[i].w;
    			if(dist[v]==-1 || dist[v]>dist[u]+w) {
    				dist[v] = dist[u] + w;
    				q.push(mp(-dist[v],v));
    			}
    		}
    	}
    }
    signed main()
    {
    	h = read(), x = read(), y = read(), z = read();
    	if(x > y) swap(x,y);
    	if(x > z) swap(x,z);
    	for(int i=0;i<x;++i) {
    		add(i,(i+y)%x,y);
    		add(i,(i+z)%x,z);
    	}
    	Dijkstra();
    	int ans = 0;
    	for(int i=0;i<x;++i) {
    		if(dist[i] > -1) {
    			if(h >= dist[i]) {
    				ans += (h-dist[i])/x + 1;
    			}
    		}
    	}
    	printf("%lld
    ",ans);
        return 0;
    }
    /*
    15
    4 7 9
    
    9
    */
    

    总结

    利用同余设计状态。

    同余最短路。

  • 相关阅读:
    ORACLE函数介绍
    msdn的javascript文章转载
    baidu的高级搜索命令
    周杰伦 青花瓷 蒲公英的约定 我不配 彩虹 歌词和下载
    谷歌百度相争 新浪渔翁得利
    tomcat+jsp web运行环境搭建
    C#2008与.NET 3.5 高级程序设计读书笔记(24) LINQ API编程
    C#2008与.NET 3.5 高级程序设计读书笔记(16) 类型反射、晚期绑定和基于特性的编程
    C#2008与.NET 3.5 高级程序设计读书笔记(15) .NET程序集入门
    C#2008与.NET 3.5 高级程序设计读书笔记(25) WCF
  • 原文地址:https://www.cnblogs.com/BaseAI/p/14053302.html
Copyright © 2011-2022 走看看