[USACO24FEB] Minimum Sum of Maximums P 题解
[USACO24FEB] Minimum Sum of Maximums P
第一步是想到转化一下这个 \(\sum \max(a_i,a_{i+1})\),我们发现 \(\max(a_i,a_{i+1}) = \frac{1}{2} \times (a_i+a_{i+1}+|a_i-a_{i+1}|)\)。那么答案前半部分就是固定的了,我们只要最小化 \(\sum |a_i-a_{i+1}|\),因为转移会用到 \(a_0\) 和 \(a_{n+1}\),所以给这两个位置赋极大值即可。
\(k\) 个固定点会将序列分成至多 \(k+1\) 段,假设我们已经知道了每个段内分配了那些数,我们来考虑怎么排是最优的。发现是从小到大排最优,这段的贡献就是 \(|V_l-mi|+|V_r-mx|+mx-mi\),那这样我们就只关心最大值和最小值了。
那么怎么列转移方程呢?需要发现一个关键性质,即每一个段的 \((mi,mx)\) 只会不相交或者包含,而不会有交,可以通过调整法证明。
我们把能用的 \(a_i\) 排序,我们会优先考虑填长度小的段,那就是区间 DP,而且看到 \(k \le 6\) 就想到状压,设 \(f_{l,r,s}\) 表示用排序后的数组的 \([l,r]\) 内的数能够填满段集合 \(s\) 的最小答案。我们要预处理出每个段的长度 \(wd_i\),以及每个状态掩码的段长之和 \(sum_s\)。
考虑转移,有几种情况。第一是把用自己区间范围的两端填好一个段,这个段的 \((mi,mx)\) 是包含了更小的段。这种转移条件是 \(len=sum_s\),就能保证是紧凑地填好的,否则区间范围如果更大的话,\(mx\) 变大,\(mi\) 变小就不优了。特判一下段长为 \(1\) 的情况。\(f_{l,r,s} \leftarrow f_{l+1,r-1,s-x}+|L_x-p_l|+|R_x-p_r|+p_r-p_l\)。
第二种情况是跳过,即 \(f_{l,r,s}=\min(f_{l+1,r,s},f_{l,r-1,s})\),在任何情况下都可以转移,表示留给下一个包住它的段。
第三种情况是合并不相交的段,考虑枚举子集,则 \(f_{l,r,s} \leftarrow f_{l,l+sum_{t}-1,t}+f_{l+sum_{t},r,s-t}\),其中 \(t \subseteq s\)。
现在我们做到了 \(O(n^23^k)\) 的时间复杂度,可以通过此题。但是我们可以发现第三种情况可以只在 \(len=sum_s\) 的时候转移,因为若 \(len >sum_s\) 则在之前肯定已经转移过了。那这样就是 \(O(n^2+n3^k)\)。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define _int __int128
#define ull unsigned long long
#define pii pair<int,int>
#define fst first
#define scd second
#define pq priority_queue
#define mkp make_pair
#define popcount(x) __builtin_popcount(x)
#define endl '\n'
int n,k,tot,m;
const int N = 3e2+10,V=(1<<7);
ll inf=1e14;
int a[N],b[N],ans=0,vis[N],wd[N];
ll L[N],R[N],sum[V];
ll f[N][N][V];
vector<int>p;
signed main(){
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
ans+=2*a[i];
}
a[0]=1e6,a[n+1]=1e6;ans+=2e6;
for(int i=1;i<=k;i++){
cin>>b[i];
vis[b[i]]=1;
}
b[0]=0,b[k+1]=n+1;
for(int i=1;i<=n;i++){
if(!vis[i])p.push_back(a[i]);
}
p.push_back(-1);
sort(p.begin(),p.end());
m=p.size()-1;
for(int i=0;i<=k;i++){
if(b[i]==b[i+1]-1){
ans+=abs(a[b[i+1]]-a[b[i]]);
continue;
}
wd[tot]=b[i+1]-b[i]-1;
L[tot]=a[b[i]],R[tot]=a[b[i+1]];
if(L[tot]>R[tot])swap(L[tot],R[tot]);
++tot;
}
for(int i=0;i<(1<<tot);i++){
for(int j=0;j<tot;j++){
if(i&(1<<j)){
sum[i]+=wd[j];
}
}
}
for(int l=0;l<=m+1;l++){
for(int r=0;r<=m+1;r++){
for(int mk=0;mk<(1<<tot);mk++){
f[l][r][mk]=(mk==0?0:inf);
}
}
}
for(int len=1;len<=m;len++){
for(int l=1;l+len-1<=m;l++){
int r=l+len-1;
for(int mk=0;mk<(1<<tot);mk++){
f[l][r][mk]=min(f[l+1][r][mk],f[l][r-1][mk]);
if(sum[mk]>len)continue;
if(sum[mk]==len){
for(int j=0;j<tot;j++){
if(mk&(1<<j)){
if(wd[j]==1&&len==1){
f[l][r][mk]=min(f[l][r][mk],abs(L[j]-p[l])+abs(R[j]-p[r]));
}else if(wd[j]>1){
f[l][r][mk]=min(f[l][r][mk],f[l+1][r-1][mk^(1<<j)]+abs(L[j]-p[l])+abs(R[j]-p[r])+p[r]-p[l]);
}
}
}
for(int s=(mk-1)&mk;s;s=(s-1)&mk){
f[l][r][mk]=min(f[l][r][mk],f[l][l+sum[s]-1][s]+f[l+sum[s]][r][mk^s]);
}
}
}
}
}
ans+=f[1][m][(1<<tot)-1];
ans/=2;ans-=2e6;
cout<<ans;
return 0;
}

浙公网安备 33010602011771号