Codeforces Round #587 (Div. 3) F - Wi-Fi dp 最短路


題意:

給定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個房間都被連上網絡了

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM