Codeforces Round #472 D - Riverside Curio 差分约束

正解据说是贪心+dp

可惜我这个人没什么脑子:)

(遇到了能用差分约束也能用dp+贪心的第二题了,真是神奇

假设有一组合法的sum
就能逆推出di,因为ai+di+1=sumi
最小化Σdi就是最小化Σsumi
考虑sumi应该满足的条件
1.是递增的
sumi>=sum(i-1)
2.sumi<=sum(i-1)+1
3.边界要sumi>=ai+1

考虑一下差分约束?
最小值跑最长路,把所有不等式转化成>=的形式
求出sum后再求一遍d就好了

#include<bits/stdc++.h>
#define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
int tot,n,m,l,r,k;
int a[maxn];
struct lys{
    int from,to,nex;
    ll val;
}e[int(1e6)];
int head[int(1e6)];
void add(int from,int to,ll val){
    tot++;e[tot].from=from;e[tot].to=to;
    e[tot].val=val;e[tot].nex=head[from];head[from]=tot;
}
int cnt[maxn];
bool vis[maxn];
ll dis[maxn];
bool spfa(void)
{
    for(int i=1;i<=n;i++)   dis[i]=LONG_LONG_MIN;
    dis[0]=0;
    deque<int> q;
    q.push_front(0);
    vis[0]=true;
    while(!q.empty())
    {
        int u;
        if(rand()&1)u=q.front(),q.pop_front();
        else u=q.back(),q.pop_back();
        vis[u]=false;
        for(int i=head[u];i;i=e[i].nex)
        {
            int v=e[i].to;ll w=e[i].val;
            if(dis[v]<dis[u]+w)
            {
                dis[v]=dis[u]+w;
                if(!vis[v])
                {
                    vis[v]=true;
                    cnt[v]++;
                    if(cnt[v]>=n+1) return false;
                     q.push_front(v);
                }
            }
        }
    }
    return true;
}

int main()
{
    fastio;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    
    for(int i=2;i<=n;i++){
        add(i-1,i,0);
        add(i,i-1,-1);
    }
    for(int i=1;i<=n;i++){
        add(0,i,a[i]+1);
    }
    if(!spfa())
    {
        cout<<-1<<endl;
        return 0; 
    }
    else {
        ll ans=0;
        for(int i=1;i<=n;i++) ans+=dis[i]-a[i]-1;
        cout<<ans;
    }
    return 0;
} 

 

posted @ 2023-02-10 18:52  liyishui  阅读(34)  评论(0编辑  收藏  举报