• 同余最短路


    最低可达层

    之下的都不可达

    之上的都可达

    同余最短路,并不是用同余来跑最短路,而是通过同余来构造某些状态,从而达到优化时间空间复杂度的目的。往往这些状态就是最短路中的点,可以类比差分约束跑最短路((f[i]+w<=f[j])构造最短路不等式(例题luogu 小k的农场))

    知识精要

    https://oi-wiki.org/graph/mod-shortest-path/

    https://www.cnblogs.com/chloris/p/11013913.html

    跳楼机

    最关键的
    for(int i=0;i<x;i++)
    	add(i,(i+y)%x,y),
    	add(i,(i+z)%x,z);
    spfa();
    统计答案
     	for(int i=0;i<x;i++) 
     		if(h>=dis[i]) 
     			ans+=(h-dis[i])/x+1;
    
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    typedef long long ll;
    const int N=2e5+10;
    inline ll read() {
    	ll x=0;char ch=getchar();
    	while(!isdigit(ch)) ch=getchar();
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return x;
    }
    ll h,dis[N],w[N];
    int hd[N],to[N],nxt[N],tot;
    
    inline void add(int x,int y,ll z) {
    	to[++tot]=y;w[tot]=z;nxt[tot]=hd[x];hd[x]=tot;
    }
    bool vis[N];
    void spfa() {
    	dis[1]=1;
    	vis[1]=1;
    	queue<int>q;
    	q.push(1);
    	while(q.size()) {
    		int x=q.front();
    		q.pop();
    		vis[x]=0;
    		for(int i=hd[x];i;i=nxt[i]) {
    			int y=to[i];
    			if(dis[y]>dis[x]+w[i]) {
    				dis[y]=dis[x]+w[i];
    				if(!vis[y]) vis[y]=1,q.push(y);
    			}
    		}
    	}
    } 
    int main() {
    	memset(dis,0x3f,sizeof(dis));
    	h=read();
    	int x,y,z,a[3];
    	a[0]=read();a[1]=read();a[2]=read();
    	sort(a,a+2);
    	x=a[0],y=a[1],z=a[2];
    	if(x==1||y==1||z==1) {
    		printf("%d
    ",h); return 0;
    	}
    	for(int i=0;i<x;i++)
     		add(i,(i+y)%x,y),
     		add(i,(i+z)%x,z);
     	spfa();
     	ll ans=0;
     	for(int i=0;i<x;i++) 
     		if(h>=dis[i]) 
     			ans+=(h-dis[i])/x+1;
     	printf("%lld
    ",ans);
    	return 0;
    }
    
    
    

    墨墨的等式

    和上面几乎一样

    ([l,r]) 套路——([1,r] - [1,l-1])

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    typedef long long ll;
    const int N=6000101;
    inline ll read() {
    	ll x=0;char ch=getchar();
    	while(!isdigit(ch)) ch=getchar();
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return x;
    }
    ll l,r,dis[N],w[N];
    int hd[N],to[N],nxt[N],tot;
    
    inline void add(int x,int y,ll z) {
    	to[++tot]=y;w[tot]=z;nxt[tot]=hd[x];hd[x]=tot;
    }
    bool vis[N];
    void spfa() {
    	dis[0]=0;//
    	vis[0]=1;
    	queue<int>q;
    	q.push(0);
    	while(q.size()) {
    		int u=q.front();//不能用x,会出锅
    		q.pop();
    		vis[u]=0;
    		for(int i=hd[u];i;i=nxt[i]) {
    			int v=to[i];
    			if(dis[v]>dis[u]+w[i]) {
    				dis[v]=dis[u]+w[i];
    				if(!vis[v]) vis[v]=1,q.push(v);
    			}
    		}
    	}
    } 
    int n,a[15];
    int main() {
    	memset(dis,0x7f,sizeof(dis));
    	n=read();l=read();r=read();
    	for(int i=1;i<=n;i++) a[i]=read();
    	sort(a+1,a+n+1);
    	int x=a[1];
    	if(x==1) {
    		printf("%lld
    ",r-l+1); return 0;
    	}
    	for(int i=0;i<x;i++)
    		for(int j=2;j<=n;j++)
     			add(i,(i+a[j])%x,a[j]);
     	spfa();
     	ll ans=0;
     	l--;
     	for(int i=0;i<x;i++) {
     		if(r>=dis[i]) 
     			ans+=(r-dis[i])/x+1;
     		if(l>=dis[i]) 
     			ans-=((l-dis[i])/x+1); 		
    	 }
     	printf("%lld
    ",ans);
    	return 0;
    }
    
    
    

    wait

    牛场围栏

    • 要求求出最大不能拼凑出来的木板长度,因此我们把最短的木板作为剩余系,扫描其他的木板并建边。题目另外说每个木板可以最多截掉m米,那么只要再扫描到每个木板的时候依次扫描这个木板能被截成的长度就好了。

    • 如何解决不能凑出来的最大木板长度?我们求出的dist[]数组是不使用(a[1]-m)的长度外能凑出来的最小长度,那么只要从dist[]中减去这个值就能得出剩余系中这类不能拼凑的最大值。对所有类都进行这样的处理,最终就能得出不能凑出的最大值。

    • 此外题目特判任意长度都可以拼成或最大值不存在输出"-1"。先考虑任意长度都能拼成,如果这个木板的长度能被削成1,那么一定可以达到任意长度,对应为if(a[1]-m<=1)。最大值不存在的情况为剩余系中一类数都无法拼成,即dist[k]没有被松弛。

      #include <queue>
      #include <cstdio>
      #include <cstring>
      #include <iostream>
      #include <algorithm>
      
      using namespace std;
      const int N=10005;
      const int M=60005;
      inline int read() {
          int x=0,f=1;char ch=getchar();
          while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
          while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
          return f*x;
      }
      
      int n,dis[N];
      int hd[N],to[M],nxt[M],w[M],tot;
      inline void add(int x,int y,int z) {
          to[++tot]=y;w[tot]=z;nxt[tot]=hd[x];hd[x]=tot;
      }
      bool vis[N];
      void spfa() {
          queue<int>q;
          memset(dis,0x3f,sizeof(dis));
          q.push(0);
          dis[0]=0;vis[0]=1;
          while(q.size()) {
              int u=q.front();q.pop();
              vis[u]=0;//开始写成了1、、、
              for(int i=hd[u];i;i=nxt[i]) {
                  int v=to[i];
                  if(dis[v]>dis[u]+w[i]) {
                      dis[v]=dis[u]+w[i];
                      if(!vis[v]) vis[v]=1,q.push(v);
                  }
              }
          }
      }
      int a[N],m,ans,x;
      int main() {
          n=read();m=read();
          for(int i=1;i<=n;i++) a[i]=read();
          sort(a+1,a+1+n);
          int x=a[1]-m;
          if(x<=1) {puts("-1");return 0;}
          for(int i=1;i<=n;i++)
              for(int j=max(a[i]-m,a[i-1]+1);j<=a[i];j++) 
                  for(int k=0;k<x;k++)
                      add(k,(k+j)%x,j);
          spfa();
          for(int i=0;i<x;i++) {
              if(dis[i]>=dis[N-1]) 
                  {puts("-1");return 0;}      
              ans=max(ans,dis[i]-x);
          }
          printf("%d
      ",ans);
          return 0;
      }
      

    货币系统

  • 相关阅读:
    SWT中如何居中显示?
    项目一 默认构造函数和带参数的构造函数
    解决ubuntu中java1.6显示中文乱码问题
    网络程序为什么要处理SIGPIPE
    SQL 数据类型大全
    poj1275 差分约束
    Oracle分组
    Android利用ViewPager实现滑动广告板
    扩展spring mvc的拦截器,实现AOP的环绕增加效果
    [Ext.Net]GridPanel之存储过程分页Sql版本
  • 原文地址:https://www.cnblogs.com/ke-xin/p/13768094.html
Copyright © 2020-2023  润新知