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; }