• Codeforces Round #587 (Div. 3) F


    题意:

    给定n个房间  要给每个房间连上网络  第i个房间连上网络的花费为i   有些房间可以装上路由器  如果装上路由器  那么左边k个和右边k个都可以被装上网络  且装路由器的费用也为i

    问最少花费使得所有的房间装上网络

    dp  用单调队列优化一下即可 :

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define repp(i,a,b) for(int i=(a);i>=(b);--i)
    #define ll long long
    #define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
    #define inf 0x3f3f3f3f
    #define CLR(A,v)  memset(A,v,sizeof A)
    //////////////////////////////////
    const int N=2e6+10;
    int n,m,l,r,st[N],k;
    char s[N];
    ll dp[N];
    
    int main()  
    {           
        scanf("%d%d",&n,&k);
        scanf("%s",s+1);
        l=r=1;st[1]=0;
        rep(i,1,n+k)
        {       
            dp[i]=dp[i-1]+i;
            if(i>k&&s[i-k]=='1')
            {   
                dp[i]=min(dp[i],dp[st[l]]+i-k);
            }   
            if(st[l]<i-2*k)l++;
            while(l<=r&&dp[st[r]]>=dp[i])r--;
            st[++r]=i;
        }       
        ll ans=1e18;
        rep(i,n,n+k)ans=min(ans,dp[i]);
        cout<<ans;
        return 0;
    }
    View Code

    比赛的时候做法是最短路

    #include<bits/stdc++.h>
    using namespace std;
    //input by bxd
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define repp(i,a,b) for(int i=(a);i>=(b);--i)
    #define RI(n) scanf("%d",&(n))
    #define RII(n,m) scanf("%d%d",&n,&m)
    #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
    #define RS(s) scanf("%s",s);
    #define ll long long
    #define inf 0x3f3f3f3f
    #define REP(i,N)  for(int i=0;i<(N);i++)
    #define CLR(A,v)  memset(A,v,sizeof A)
    //////////////////////////////////
    const int N=1e6;
    const int M=1e6;
    int head[M];
    int pos;
    struct Edge
    {
        ll v;int to,nex;
    }edge[M];
    void add(int a,int b,ll c)
    {
        edge[++pos]=Edge{c,b,head[a]};
        head[a]=pos;
    }
    struct Node
    {
        ll d;int id;
        bool operator<(const Node& b)const
        {
            return d>b.d;
        }
    };
    ll dis[N];
    int vis[N];
    int n,m,k,a,b,c,t;
    char s[N];
    void dijkstra(int s)
    {
        rep(i,0,n+1)dis[i]=1e18;
        dis[s]=0;
        priority_queue<Node>q;
        q.push(Node{0,s});
        while(!q.empty())
        {
            Node u=q.top();q.pop();
            if(vis[u.id])continue;
            vis[u.id]=1;
            for(int i=head[u.id];i;i=edge[i].nex)
            {
                int v=edge[i].to;
                if(u.d+edge[i].v<dis[v])
                {
                    dis[v]=u.d+edge[i].v;
                    q.push(Node{dis[v],v});
                }
            }
        }
    }
    int main()
    {
        scanf("%d%d",&n,&k);
        scanf("%s",s+1);
        rep(i,1,n)
        {
            add(i,i+1,1ll*i);
            add(i,i-1,1ll*0);
            if(s[i]=='1')
            add( max(1,i-k), min( n+1,i+k+1 ), 1ll*i );
        }
        add(n+1,n,1ll*0);
        dijkstra(1);
        cout<<dis[n+1];
        return 0;
    }
    View Code

    设置一个超级汇点t
    第i个点连i+i 长度为i 表示将第i个房间连网所需要的费用 (第n个房间连t)

    如果第i个点可以装路由器 那么连 i-k到i+k+1 费用为i
    表示 i-k到i+k范围内的房间都可以被i点的路由器控制    那么这些房间都被完成了 所以跳到i+k+1

    有一些特殊情况需要回溯(就是两个路由器管辖范围相交的情况) 所以每个点i 连i-1 费用为0 可以根据样例看看

    所以如果跑到t点就说明了n个房间都被连上网络了

  • 相关阅读:
    Linux配置Nginx负载均衡
    linux虚拟机ping不通主机和外网(包括刚装系统遇到的一些问题)
    MySQL的主从复制
    ubuntu下安装php
    ubuntu下sudo apt-get update Sources 404 Not Found 解决方法
    java 中类的加载顺序
    PHP生成各种验证码和Ajax验证
    PHP算法之二分查找和顺序查找
    ThinkPHP中SQL调试方法
    mysql 处理中文乱码问题
  • 原文地址:https://www.cnblogs.com/bxd123/p/11566746.html
Copyright © 2020-2023  润新知