P12675 「LAOI-8」Boundary
思路
首先考虑如何使得整个区间变为 $-10^9$,显然一定有一次修改左端点为 $1$,有一次修改右端点为 $n$,因为无法通过增加 $1$ 使得某个数变为一个极小值(当然不考虑上溢出)。
那么就得到了一种比较普通的方法,取 $1<l<r<n$,那么答案即为 $|a_1-a_l|+l+|a_n-a_r|+(n-r+1)+(r-l+1)$。
化简式子可得 $|a_1-a_l|+|a_n-a_r|+n+2$,可以发现与 $l,r$ 的位置无关,只与 $a_1,a_l$ 与 $a_n,a_r$ 的大小有关。
考虑两个 DP 数组 $f,g$,$f_i$ 表示 $x\in(1,i],\min |a_1-a_x|$,$g_i$ 表示 $x\in[i,n),\min |a_n-a_x|$,这两个数组也是好做的,代码大概是:
1 2 3 f[1 ]=inf;g[n]=inf; rep (i,2 ,n)f[i]=min (f[i-1 ],abs (a[1 ]-a[i]));per (i,n-1 ,1 )g[i]=min (g[i+1 ],abs (a[n]-a[i]));
然后直接遍历一个最大的 $l$,答案即为 $f_l+g_r+n+2$。
还有另一种比较普通的方法,就是取 $1<l<r<n$,那么答案即为 $|a_1-a_{l-1}|+l-1+|a_n-a_{r+1}|+(n-r)+|a_l-a_r|+(r-l+1)$。
化简后就是 $|a_1-a_{l-1}|+|a_n-a_{r+1}|+|a_l-a_r|+n$。
注意到这个式子与上面的相似,并且当 $|a_l-a_r|\ge 2$ 的时候就严格劣于上面的式子,所以 $|a_l-a_r|$ 一定只能取 $1$。
那么用一个数组 $p
$ 记录每个值出现的位置即可简单的做出。
还是放个代码:
1 2 3 4 5 6 7 rep (i,1 ,n)read (a[i]),p[a[i]]=i;rep (i,3 ,n){ if (a[i]==n)continue ; int l=min (i,p[a[i]+1 ]); int r=max (i,p[a[i]+1 ]); if (3 <=l&&r<=n-2 )ans=min (ans,abs (a[l-1 ]-a[1 ])+abs (a[r+1 ]-a[n])+n+1 ); }
然而如果 $r=l+1$,则不需要对 $[l,r]$ 区间再进行一次操作,故答案也可以取到 $|a_1-a_l|+|a_r-a_n|+n$。
还有一种情况就是直接使 $a_1=a_n$,然后对 $[1,n]$ 进行操作,故答案也可以取到 $|a_1-a_n|+n$。
这两种情况特判掉即可。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 #include <bits/stdc++.h> #define fir first #define sec second #define int long long #define pii pair<int,int> #define fep(i,s,e) for(int i=s;i<e;i++) #define pef(i,s,e) for(int i=s;i>e;i--) #define rep(i,s,e) for(int i=s;i<=e;i++) #define per(i,s,e) for(int i=s;i>=e;i--) namespace FastIO{ template <typename T>inline void read (T &x) { x=0 ;int f=1 ;char c=getchar (); for (;!isdigit (c);c=getchar ())if (c=='-' )f=-1 ; for (;isdigit (c);c=getchar ())x=(x<<1 )+(x<<3 )+(c^48 );x*=f; } template <typename T,typename ...Args> inline void read (T &x,Args&...args) { read (x); read (args...); } template <typename T>void print (T x) { if (x<0 )x=-x,putchar ('-' ); if (x>9 )print (x/10 ); putchar ((x%10 )^48 ); } } using namespace std;using namespace FastIO;const int N=1e6 +7 ;const int inf=1e9 ;int T,n,a[N];int f[N],g[N],p[N];signed main () { read (T); while (T--){ read (n);int ans=inf; rep (i,1 ,n)read (a[i]),p[a[i]]=i; rep (i,3 ,n){ if (a[i]==n)continue ; int l=min (i,p[a[i]+1 ]); int r=max (i,p[a[i]+1 ]); if (3 <=l&&r<=n-2 )ans=min (ans,abs (a[l-1 ]-a[1 ])+abs (a[r+1 ]-a[n])+n+1 ); } f[1 ]=inf;g[n]=inf; rep (i,2 ,n)f[i]=min (f[i-1 ],abs (a[1 ]-a[i])); per (i,n-1 ,1 )g[i]=min (g[i+1 ],abs (a[n]-a[i])); rep (i,2 ,n-2 ){ int l=i,r=i+1 ; ans=min (ans,f[l]+g[r]+n+2 ); ans=min (ans,abs (a[1 ]-a[l])+abs (a[r]-a[n])+n); } ans=min (ans,abs (a[1 ]-a[n])+n); print (ans);puts ("" ); } }
后记
其实这道题还是好想的,只是情况比较多,需要慢慢讨论,仔细考虑边界条件。