zoukankan      html  css  js  c++  java
  • Codeforces Round #600 (Div. 2)E F

    题:https://codeforces.com/contest/1253/problem/E

    题意:给定n个信号源,俩个参数x和s,x代表这个信号源的位置,s代表这个信号源的波及长度,即这个信号源可以遍及[x-s,x+s]范围,然后你可以消耗一个代价来换取某个信号源的s加1,

       给定m,问信号覆盖1到m所有数的最小代价是什么

    分析:考虑dp[i]:表示[i+1,m]被覆盖所要花费的最小代价,dp[0]就是答案,枚举[0,m-1],从后往前枚举,若i+1在某个初始范围里面则dp[i]=dp[i+1],否则

       就枚举在i位置后面的信号源 ,然后贪心取dp+cost的最小值

    #include<bits/stdc++.h>
    using namespace std;
    const int M=2e5+5;
    typedef long long ll;
    struct node{
        int x,s;
        bool operator <(const node &b)const{
            return x<b.x;
        }
    }a[100];
    int dp[M];
    map<int,int>mp;
    int main(){
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)
            scanf("%d%d",&a[i].x,&a[i].s);
    
        sort(a,a+n);
        dp[m]=0;
        for(int i=0;i<m;i++)
            dp[i]=m-i;
        for(int i=m-1;i>=0;i--){
            for(int j=0;j<n;j++){
                int l=max(0,a[j].x-a[j].s);
                int r=min(m,a[j].x+a[j].s);
                if(l<=i+1&&i+1<=r){
                    dp[i]=dp[i+1];
                    break;
                }
                if(i<l){
                    int dis=(l-i)-1;
                    int RR=min(m,r+dis);
                    dp[i]=min(dp[i],dis+dp[RR]);
                }
            }
    
        }
        printf("%d
    ",dp[0]);
        return 0;
    }
    View Code

    F:https://codeforces.com/contest/1253/problem/F

     分析:题目给定的起点和终点总是充电站,所以要保证机器人要可以走到最近的充电站且从充电站返回的时候不能减少电量(其实这俩个要求是一样的)

        充电站到普通点最近,我们考虑做这些充电站的多源最短路,然后就可以找出普通点到最近充电站的距离,在这里我们定义为d[u]。
        我们假设x为机器人到u点还剩的电量,机器人的容量为c,显然x要大于等于d[u](因为终点肯定是充电站,所以点u走到最近的充电站无疑是个正确的贪心策略)得到条件:x>=d[u](x<=c-d[u])),且x=c-d[u]
        然后我们考虑俩个一般点u,v,之间的消耗为w,那么要满足x-w>=d[v],因为u到达v后要保证v在达到终点充电站前还可以走向最近的充电站,带入上面分析的x,得(c-d[u])-w>=d[v],即d[u]+d[v]+w<=c;
        因此我们新建一个图,要求最小容量,那么在u,v之间建一条d[u]+d[v]+w边权的边,那么题目的问题就转化为找a到b路径中权值最大的边(这里的权值是新的边权)
        因为这里我们要找最小的满足机器人可走容量,也就是说是在尽量小的条件下挑出最大值,这就和MST的很像了。
        因为有多个询问,所以暴力一下在MST中们开个对每一点开一个set,记录经过并查集处理后在这个集合中的点,然后当前找到的w,若查询到在这俩个集合中,那么这就是我们上面分析要的答案了

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i,a,b) for(int i=(a);i<=(b);++i)
    #define dep(i,a,b) for(int i=(a);i>=(b);--i)
    #define pb push_back
    #define pii pair<int,int>
    typedef long long ll;
    const int maxn=(int)1e5+100;
    const int mod=(int)1e9+7;
    const ll INF=(ll)1ll<<61;
    int n,m,k,q,fa[maxn];
    ll dis[maxn],ans[maxn*6];
    vector<pair<int,ll> > g[maxn*6];
    vector<pii> que[maxn];
    vector<tuple<ll,int,int> > e;
    set<int> ele[maxn];
    void dij(){
        priority_queue<pair<ll,int> > Q;
        rep(i,1,n){
            if(i<=k) Q.push({0,i});
            else dis[i]=INF;
        }
        while(!Q.empty()){
            int u=Q.top().second;Q.pop();
            for(auto [v,w]:g[u]){
                if(dis[u]+w<dis[v]){
                    dis[v]=dis[u]+w;
                    Q.push({-dis[v],v});
                }
            }
        }
    }
    void init(){rep(i,1,n) fa[i]=i,ele[i].insert(i);}
    int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
    int main(){
        scanf("%d%d%d%d",&n,&m,&k,&q);
        rep(i,1,m){
            int u,v;ll w;scanf("%d%d%lld",&u,&v,&w);
            g[u].pb({v,w});g[v].pb({u,w});
        }
        dij();
        rep(u,1,n) for(auto [v,w]:g[u]) if(u<v) e.pb({dis[u]+dis[v]+w,u,v});
        sort(e.begin(),e.end());
        rep(i,1,q){
            int u,v;scanf("%d%d",&u,&v);
            que[u].pb({v,i});que[v].pb({u,i});
        }
        init();
        for(auto [w,x,y]:e){
            x=find(x);y=find(y);
            if(x==y) continue;
            if(ele[x].size()<ele[y].size()) swap(x,y);降低时间复杂度而已
            fa[y]=x;
            for(auto u:ele[y]) for(auto [v,id]:que[u]) if(ele[x].count(v)) ans[id]=w;
            for(auto u:ele[y]) ele[x].insert(u);
        }
        rep(i,1,q) printf("%lld
    ",ans[i]);
    }
    View Code
  • 相关阅读:
    linux进程管理
    使用PL/SQL Developer 学习pl/sql
    Linux入门到放弃之一《在VMware虚拟机中安装Linux系统(RedHat)》
    解决Java连接Oracle 12c存在的问题
    Linux安装64位Mysql5.7.22
    在centos下启动nginx出现Failed to start nginx.service:unit not found
    windows10下IntelliJ IDEA使用logback设置日志输出目录
    Windows下mysql5.6升级到5.7的方法
    Spring+Hibernate+Struts2整合之实现登录功能
    Hibernate关系映射之many-to-many(多对多)
  • 原文地址:https://www.cnblogs.com/starve/p/11876347.html
Copyright © 2011-2022 走看看