zoukankan      html  css  js  c++  java
  • csps模拟92数列,数对,最小距离题解

    题面:https://www.cnblogs.com/Juve/articles/11767225.html

    数列:

    简化题意:已知a,b,c,求满足$a*x+b*y=c$的$x+y$最小值

    然后ex_gcd硬刚就好了,若c为负,则取abs

    如果我们设a<b,最优决策点就是x的最小正整数解和最大负整数解

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define int long long
     6 using namespace std;
     7 const int MAXN=1e5+5;
     8 int n,a,b,g,val,x,y,ans=0;
     9 int ex_gcd(int a,int b,int &x,int &y){
    10     if(!b){
    11         x=1,y=0;
    12         return a;
    13     }
    14     int d=ex_gcd(b,a%b,x,y);
    15     int t=x;
    16     x=y,y=t-a/b*x;
    17     return d;
    18 }
    19 signed main(){
    20     scanf("%lld%lld%lld",&n,&a,&b);
    21     if(a>b) swap(a,b);
    22     g=ex_gcd(a,b,x,y);
    23     a/=g,b/=g;
    24     x=(x%b+b)%b;
    25     for(int i=1;i<=n;++i){
    26         scanf("%lld",&val);
    27         if(val<0) val=-val;
    28         if(val%g){
    29             puts("-1");
    30             return 0;
    31         }
    32         val/=g;
    33         int p=(x*val%b+b)%b;
    34         int q=(val-a*p)/b;
    35         ans+=min(abs(p)+abs(q),abs(p-b)+abs(q+a));
    36     }
    37     printf("%lld
    ",ans);
    38     return 0;
    39 }
    View Code

    数对:

    队长快跑加了权值

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define int long long
     6 using namespace std;
     7 const int MAXN=1e5+5;
     8 int n,ans=0,sta[MAXN<<1],top=0;
     9 struct node{
    10     int a,b,w;
    11     friend bool operator < (node p,node q){
    12         return p.a+p.b<q.a+q.b;
    13     }
    14 }p[MAXN];
    15 int tr[MAXN<<3],laz[MAXN<<3];
    16 void down(int k){
    17     tr[k<<1]+=laz[k],tr[k<<1|1]+=laz[k];
    18     laz[k<<1]+=laz[k],laz[k<<1|1]+=laz[k];
    19     laz[k]=0;
    20 }
    21 int query(int k,int l,int r,int opl,int opr){
    22     if(opl<=l&&r<=opr) return tr[k];
    23     if(laz[k]) down(k);
    24     int mid=(l+r)>>1,res=0;
    25     if(opl<=mid) res=max(res,query(k<<1,l,mid,opl,opr));
    26     if(opr>mid) res=max(res,query(k<<1|1,mid+1,r,opl,opr));
    27     return res;
    28 }
    29 void update(int k,int l,int r,int opl,int opr,int val){
    30     if(opl<=l&&r<=opr){
    31         tr[k]+=val;
    32         laz[k]+=val;
    33         return ;
    34     }
    35     if(laz[k]) down(k);
    36     int mid=(l+r)>>1;
    37     if(opl<=mid) update(k<<1,l,mid,opl,opr,val);
    38     if(opr>mid) update(k<<1|1,mid+1,r,opl,opr,val);
    39     tr[k]=max(tr[k<<1],tr[k<<1|1]);
    40 }
    41 void change(int k,int l,int r,int opt,int val){
    42     if(l==r){
    43         tr[k]=max(tr[k],val);
    44         return ;
    45     }
    46     if(laz[k]) down(k);
    47     int mid=(l+r)>>1;
    48     if(opt<=mid) change(k<<1,l,mid,opt,val);
    49     else change(k<<1|1,mid+1,r,opt,val);
    50     tr[k]=max(tr[k<<1],tr[k<<1|1]);
    51 }
    52 signed main(){
    53     //freopen("pair.in","r",stdin);
    54     scanf("%lld",&n);
    55     for(int i=1;i<=n;++i){
    56         scanf("%lld%lld%lld",&p[i].a,&p[i].b,&p[i].w);
    57         sta[++top]=p[i].a,sta[++top]=p[i].b;
    58     }
    59     sort(p+1,p+n+1);
    60     sort(sta+1,sta+top+1);
    61     top=unique(sta+1,sta+top+1)-sta-1;
    62     for(int i=1;i<=n;++i){
    63         p[i].a=lower_bound(sta+1,sta+top+1,p[i].a)-sta;
    64         p[i].b=lower_bound(sta+1,sta+top+1,p[i].b)-sta;
    65     }
    66     for(int i=1;i<=n;++i){
    67         if(p[i].a<p[i].b){
    68             update(1,1,top,p[i].a+1,p[i].b,p[i].w);
    69             int t=query(1,1,top,1,p[i].a)+p[i].w;
    70             change(1,1,top,p[i].a,t);
    71         }else{
    72             int t=query(1,1,top,1,p[i].b)+p[i].w;
    73             change(1,1,top,p[i].a,t);
    74         }
    75     }
    76     printf("%lld
    ",tr[1]);
    77     return 0;
    78 }
    View Code

    最小距离:

    多源点spfa,把所有特殊点作为远点跑spfa,此时的dis数组意义就是这个点到所有特殊点中最小那一个的距离,同时记录这个点是从那一个点转移而来,

    跑完后枚举所有边,如果边的两段的点不是由同一个特殊点更新而来,那么用dis[u]+dis[v]+val[u,v]更新两个特殊点

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #define int long long
    using namespace std;
    const int MAXN=2e5+5;
    int n,m,p,x[MAXN];
    int to[MAXN<<1],nxt[MAXN<<1],pre[MAXN],val[MAXN<<1],cnt=0,fr[MAXN<<1];
    void add(int u,int v,int w){
    	++cnt,to[cnt]=v,fr[cnt]=u,nxt[cnt]=pre[u],pre[u]=cnt,val[cnt]=w;
    }
    int dis[MAXN],fro[MAXN],ans[MAXN];
    bool vis[MAXN];
    queue<int>q;
    void spfa(){
    	memset(dis,0x3f,sizeof(dis));
    	memset(vis,0,sizeof(vis));
    	for(int i=1;i<=p;++i){
    		dis[x[i]]=0,vis[x[i]]=1;
    		q.push(x[i]);
    		fro[x[i]]=x[i];
    	}
    	while(!q.empty()){
    		int x=q.front();
    		q.pop();
    		for(int i=pre[x];i;i=nxt[i]){
    			int y=to[i];
    			if(dis[y]>dis[x]+val[i]){
    				dis[y]=dis[x]+val[i];
    				fro[y]=fro[x];
    				if(!vis[y]) q.push(y),vis[y]=1;
    			}
    		}
    		vis[x]=0;
    	}
    }
    signed main(){
    	//freopen("distance.in","r",stdin);
    	scanf("%lld%lld%lld",&n,&m,&p);
    	for(int i=1;i<=p;++i) scanf("%lld",&x[i]);
    	for(int i=1,u,v,w;i<=m;++i){
    		scanf("%lld%lld%lld",&u,&v,&w);
    		add(u,v,w),add(v,u,w);
    	}
    	memset(ans,0x3f,sizeof(ans));
    	spfa();
    	for(int i=1;i<=cnt;i+=2){
    		int u=fr[i],v=to[i];
    		if(fro[u]!=fro[v]){
    			ans[fro[u]]=min(ans[fro[u]],dis[u]+dis[v]+val[i]);
    			ans[fro[v]]=min(ans[fro[v]],dis[u]+dis[v]+val[i]);
    		}
    	}
    	for(int i=1;i<=p;++i) printf("%lld ",ans[x[i]]);
    	puts("");
    	return 0;
    }
    
  • 相关阅读:
    Silverlight开发历程—动画(实现跑马灯效果)
    将小写金额转换成为大写
    Silverlight—C#代码实现变形特效
    Silverlight开发历程—C#代码添加动画
    Silverlight开发历程—动画(线性动画)
    仿腾讯登录验证码
    光线CMS系统,如何显示幻灯片
    Winform打开窗口时出现“确保已安装文件类型.cs的应用程序”的解决方法
    #2003 – 服务器没有响应 MySQL 无法启动
    根据对方提供的URL获取返回的数据流并保存为XML
  • 原文地址:https://www.cnblogs.com/Juve/p/11767292.html
Copyright © 2011-2022 走看看