zoukankan      html  css  js  c++  java
  • Luogu P3403 跳楼机|同余最短路

    题意:给出跳楼机的4个操作,分别为
    1.向上移动(x)层;

    2.向上移动(y)层;

    3.向上移动(z)层;

    4.回到第一层。 显然,并不需要

    求从第一层开始,能到达(1)(h)中的多少层?

    (1<=h<=2^{63}-1)

    (1<=x, y, z<=100000)

    题解:

    好像可以直接(DP)?

    布星啊,看下数据范围。

    那先来推推定理?

    接下来假设(xle yle z)

    对于一个数(k),若它能到达,则(k+x,k+2x,k+...)(均(le h))均能到达,(y)(z)同理

    那我们可以选(x)为模数,若(k)可以,上面的都可以!显然可以设(f[i])表示最小的可以用(y,z)表示出来的数。计算答案只需求(sumlimits^{x-1}_{i=0}(h-f[i])/x+1),空间是质的飞跃

    等等,你这根本不是递推啊,dp个鬼啊。

    好吧,确实不行,但看下转移?

    (f[i+y]=f[i]+y,f[i+z]=f[i]+z)

    似曾相识有没有?

    这与最短路非常相像完 全 一 致!

    那就用最短路代替,从(i->(i+y)\%x)边权(y),从(i->(i+z)\%x)边权(z)

    自此,算法成型。

    这就是同余系最短路

    tips:应从(1\%x)开始跑最短路!

    #include<bits/stdc++.h>
    using namespace std;
    long long cc,to[300100],net[300100],fr[300100],l[300100],g;
    long long ans,hh,f[300100],h[300100],ha[300100],x[4];
    bool vis[300100];
    void addedge(long long u,long long v,long long len)
    {
    	cc++;
    	to[cc]=v;net[cc]=fr[u];fr[u]=cc;l[cc]=len;
    }
    void add(long long x,long long y)
    {
    	g++;
    	h[g]=x;ha[g]=y;
    	long long fa=g/2,so=g;
    	while (h[fa]>h[so]&&fa)
    	{
    		swap(h[fa],h[so]);
    		swap(ha[fa],ha[so]);
    		so=fa;fa/=2;
    	}
    }
    long long del()
    {
    	long long re=ha[1];
    	h[1]=h[g];ha[1]=ha[g];g--;
    	long long fa=1,so=2;
    	if (h[so]>h[so+1]&&so+1<=g) so++;
    	while (h[fa]>h[so]&&so<=g)
    	{
    		swap(h[fa],h[so]);
    		swap(ha[fa],ha[so]);
    		fa=so;so*=2;
    		if (h[so]>h[so+1]&&so+1<=g) so++;
    	}
    	return re;
    }
    void dij()
    {
    	for (long long i=0;i<x[0];i++)
    	  vis[i]=false,f[i]=9223372036854775807;
    	f[1%x[0]]=1;
    	add(1,1%x[0]);
    	while (g)
    	{
    		long long x=del();
    		if (vis[x]) continue;
    		vis[x]=true;
    		for (long long i=fr[x];i;i=net[i])
    		{
    			if (f[to[i]]>f[x]+l[i])
    			{
    				f[to[i]]=f[x]+l[i];
    				add(f[to[i]],to[i]);
    			}
    		}
    	}
    }
    int main()
    {
    	cin>>hh;
    	cin>>x[0]>>x[1]>>x[2];
    	sort(x+0,x+3);
    	for (long long i=0;i<x[0];i++)
    	{
    		addedge(i,(i+x[1])%x[0],x[1]);
    		addedge(i,(i+x[2])%x[0],x[2]);
    	}
    	dij();
    	for (long long i=0;i<x[0];i++)
    	{
    		if (f[i]>hh) continue;
    		ans+=(hh-f[i])/x[0]+1;
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    

    习题[国家集训队]墨墨的等式 BZOJ链接


    参考资料
    【1】https://www.luogu.org/problemnew/solution/P3403

  • 相关阅读:
    Open source cryptocurrency exchange
    Salted Password Hashing
    95. Unique Binary Search Trees II
    714. Best Time to Buy and Sell Stock with Transaction Fee
    680. Valid Palindrome II
    Java compiler level does not match the version of the installed Java project facet.
    eclipse自动编译
    Exception in thread "main" java.lang.StackOverflowError(栈溢出)
    博客背景美化——动态雪花飘落
    java九九乘法表
  • 原文地址:https://www.cnblogs.com/fmj123/p/Luogu3403.html
Copyright © 2011-2022 走看看