正解据说是贪心+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;
}