本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!
题目链接:BZOJ1484
正解:贪心
解题报告:
做这道题做的我也是醉了…
本来是找仙人掌题目的,搜索BZOJ仙人掌-->BZOJ1484!
看了一下题目,excuse me?这跟仙人掌有啥关系?
上网一搜题解,都说的很含糊,做法都是一个不知道怎么证明正确性的贪心…
窝这么弱就记住这个算法好了…
考虑我先做出所有点能取到的下界b,那么我不可能比这个还要低,只需要把一些点升高,而我升高的时候必然是对于一段进行操作,然后维护接口处是否合法就能在保证合法性的情况下尽可能更优。
我的操作位置,是需要升高的-需要降低的个数最大的那个位置。
然后反复做,总复杂度$O(n^2)$…
//It is made by ljh2000 #include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include <cmath> #include <algorithm> #include <ctime> #include <vector> #include <queue> #include <map> #include <set> #include <string> #include <complex> using namespace std; typedef long long LL; typedef long double LB; typedef complex<double> C; const double pi = acos(-1); const LL inf = (1LL<<60); const int MAXN = 5011; int n,d; LL a[MAXN],b[MAXN]; LL ans; inline int getint(){ int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar(); if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w; } inline void work(){ int T=getint(); while(T--) { n=getint(); d=getint(); for(int i=1;i<=n;i++) a[i]=getint(); 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; LL minl,maxl,tot,quan,pos; while(a[n]!=b[n]) { minl=inf; maxl=-inf; tot=0; for(int i=n;i>1;i--) { if(b[i]<a[i]) minl=min(minl,a[i]-b[i]),tot++; else tot--; if(tot>maxl && b[i]!=b[i-1]+d) maxl=tot,pos=i,quan=minl; } quan=min(quan,b[pos-1]+d-b[pos]); for(int i=pos;i<=n;i++) b[i]+=quan; } ans=0; for(int i=1;i<=n;i++) ans+=abs(a[i]-b[i]); printf("%lld ",ans); } } int main() { work(); return 0; }