• 同余最短路


    看上去就很废……

    题意

    有一个长度为 \(n\) 的数列 \(a\),我任意造出一个数组 \(b\),记 \(s=\sum a_ib_i\),求 \(s\)\([0,M]\) 中有多少种取值。

    解法

    发现,如果 \(s\) 可以取到,则 \(s+ka_1\) 也可以取到。

    所以我们就先不用 \(a_1\),用其它数拼凑出一个数字 \(x\),那么 \(x+ka_1\) 都可以被取到。

    所以在模 \(a_1\) 的情况下,我们需要知道最少要多少才能有数字 \(0,1,2,...,a_1-1\)。也就是说,为了在模意义下 \(=x\),在不模的意义下最小是多少。比如 \(M=100,a_1=10\),如果我能拼出 23 和 93,由于拼出 23 后不断加 \(a_1\) 可以得到 23,33,43……93,所以拼出 93 是没用的。我们只用找到在模 \(a_1\) 意义下,拼出 3 的最小值就可以了。

    于是我们就建立 \(0,1,...,a_1-1\) 这些点。我们知道一个 \(a_i\)\(i\neq 1\)),可以让 \(x\) 变成 \((x+a_i) \bmod a_1\)。所以我们枚举除了 1 的每个 \(a_i\),连边 \(j\to (j+a_i)\bmod a_1:a_i\)

    然后从 0 开始跑最短路。然后我们就知道了拼出模 \(a_1\) 的情况下的数字最小值 \(dis_i\)

    于是答案就是 \(\Large \sum\limits_{i=0}^{a_1-1} (1+\frac{M-dis_i}{a_1})\),下取整。

    由于算法,我们肯定会让 \(a_1\)\(a\) 中最小值。时间复杂度为 \(O(\ na_1+(n+a_1)\log (n+a_1)\ )\)( 建图 + dij )。

    例题

    洛谷,跳楼机

    #include<bits/stdc++.h>
    #define rep(i,x,y) for(int i=x;i<=y;++i)
    #define per(i,x,y) for(int i=x;i>=y;--i)
    #define mar(o) for(int E=fst[o];E;E=e[E].nxt)
    #define v e[E].to
    #define lon long long
    using namespace std;
    const int n7=101234,m7=501234;
    struct dino{int to,nxt,w;}e[m7];
    int a[5],ecnt,fst[n7],u[n7];
    lon N,ans,dis[n7];
    
    lon rd(){
    	lon shu=0;bool fu=0;char ch=getchar();
    	while( !isdigit(ch) ){if(ch=='-')fu=1;ch=getchar();}
    	while( isdigit(ch) )shu=(shu<<1)+(shu<<3)+ch-'0',ch=getchar();
    	return fu?-shu:shu;
    }
    
    void edge(int p,int q,int w){
    	ecnt++;
    	e[ecnt]=(dino){q,fst[p],w};
    	fst[p]=ecnt;
    }
    
    void dijk(){
    	memset(dis,0x3f,sizeof dis),dis[1]=0;
    	priority_queue < pair<lon,int> > que;
    	que.push( make_pair(0,1) );
    	while( !que.empty() ){
    		int o=que.top().second;que.pop();
    		if(u[o])continue;
    		u[o]=1;
    		mar(o){
    			if(dis[v]>dis[o]+e[E].w){
    				dis[v]=dis[o]+e[E].w;
    				if(!u[v])que.push( make_pair(-dis[v],v) );
    			}
    		}
    	}
    }	
    
    int main(){
    	N=rd()-1,a[1]=rd(),a[2]=rd(),a[3]=rd();
    	sort(a+1,a+4);
    	rep(i,0,a[1]-1){
    		edge(i+1,(i+a[2])%a[1]+1,a[2]);
    		edge(i+1,(i+a[3])%a[1]+1,a[3]);
    	}
    	dijk();
    	rep(i,1,a[1])if(dis[i]<=N)ans=ans+(N-dis[i])/a[1]+1;
    	printf("%lld",ans);
    	return 0;
    }
    
  • 相关阅读:
    第02周学习提升建议:【python安装、变量、输入输出、流程、循环】--【第五篇】流程、循环
    向gitlab上传本地项目
    [jenkins+gitlab+postman] 持续集成
    linux 上安装newman
    【python】读取cfg/ini/txt配置文件
    【CI/CD】docker部署gitlab,并且本地拉取gitlab代码成功
    【CI/CD】docker部署Jenkins
    【TCP知识】03_Linux查看TCP连接状态
    【nginx知识】02_【转载】nginx反向代理时保持长连接
    【TCP/IP知识】02_【转载】TCP 半连接队列和全连接队列
  • 原文地址:https://www.cnblogs.com/BlankAo/p/15883639.html
Copyright © 2020-2023  润新知