bzoj 1484 [HNOI2009]通往城堡之路 贪心

来源:互联网 发布:经济学数据库 编辑:程序博客网 时间:2024/04/30 11:25

感觉这题还是挺迷的。。。
并不会证这个玩意为什么是对的。。。

固定第一个点的值,其他点的值取a[i]-(i-1)*d(这个点能取的最小值)
然后每次找一个后缀,把这个后缀所有数加一个大于0的值,且保证这是最优的取法下加的尽量大的值。
由于每次把一个数加到最值所以复杂度是O(n2)的。

#include <bits/stdc++.h>using namespace std;#define N 51000#define ll long longint T,n,d;int a[N];ll b[N],val,inf,num,pos,mx,tar,ans;int main(){    //freopen("tt.in","r",stdin);    scanf("%d",&T);    while(T--)    {        scanf("%d%d",&n,&d);        for(int i=1;i<=n;i++)            scanf("%d",&a[i]);        if(abs(a[n]-a[1])>(ll)d*(n-1))            {puts("impossible");continue;}        b[1]=a[1];        for(int i=2;i<=n;i++)            b[i]=b[i-1]-d;        inf=1e18;        while(b[n]!=a[n])        {            val=inf;mx=-inf;num=0;            for(int i=n;i>1;i--)            {                if(b[i]<a[i])                    val=min(val,a[i]-b[i]),num++;                else num--;                if(num>mx&&b[i]!=b[i-1]+d)                    mx=num,pos=i,tar=val;            }            tar=min(tar,b[pos-1]+d-b[pos]);            for(int i=pos;i<=n;i++)                b[i]+=tar;        }        ans=0;        for(int i=1;i<=n;i++)            ans+=abs(a[i]-b[i]);        printf("%lld\n",ans);    }    return 0;}
0 0
原创粉丝点击