专栏文章

题解:AT_cf16_exhibition_final_f Intervals

AT_cf16_exhibition_final_f题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@min1c3co
此快照首次捕获于
2025/12/01 18:57
3 个月前
此快照最后确认于
2025/12/01 18:57
3 个月前
查看原文

AT_cf16_exhibition_final_f Intervals 题解


知识点

贪心,DP。

分析

可以证明有一个区间一定不动,分奇偶即可。
接下来很直观地可以感受到要把区间分到两边,且短的放在离不动区间近的会更优,所以我们降序排序。
进一步地,把区间对半分开放到左右也会让答案不劣,这就与初中的绝对值问题类似。
我们可以列出答案的表达式:设左边选到了第 ii 个,右边选到了第 jj 个。
  • 不动的区间,设为 (Lx,Rx)(L_x,R_x),贡献为 00
  • 放到左边的区间,设为 (L1,i,R1,i)(L_{1,i},R_{1,i}),贡献为 (i1)(R1,iL1,i)+(R1,iLx)(i-1)(R_{1,i}-L_{1,i})+(R_{1,i}-L_x)
  • 放到右边的区间,设为 (L2,j,R2,j)(L_{2,j},R_{2,j}),贡献为 (j1)(R2,jL2,j)+(RxL2,j)(j-1)(R_{2,j}-L_{2,j})+(R_x-L_{2,j})
那么可以考虑拆贡献,这里要分为奇偶两种情况:
  1. nn 为奇数:
    那么较为简单,设 m=n2m=\lfloor \frac{n}{2} \rfloor,左边和右边各会选 mm 个区间。贡献为:
    i[(i1)(R1,iL1,i)+R1,i]+j[(j1)(R1,jL1,j)L1,j]+m(RxLx)\sum_{i}[(i-1)(R_{1,i}-L_{1,i}) + R_{1,i}] + \sum_{j}[(j-1)(R_{1,j}-L_{1,j}) - L_{1,j}] + m(R_x-L_x) \\
  2. nn 为偶数:
    考虑不动的区间随意取中间两个其中一个即可。设 m=n2m=\lfloor \frac{n}{2} \rfloor,左边取 m1m-1 个,右边取 mm 个。贡献为:
    i[(i1)(R1,iL1,i)+R1,i]+j[(j1)(R1,jL1,j)L1,j]+mRx(m1)Lx\sum_{i}[(i-1)(R_{1,i}-L_{1,i}) + R_{1,i}] + \sum_{j}[(j-1)(R_{1,j}-L_{1,j}) - L_{1,j}] + mR_x-(m-1)L_x \\
那么 DP 状态就是 fl,r,0/1f_{l,r,0/1} 表示左边选了 ll 个,右边选了 rr 个,0/10/1 表示是否已经选取了不动的区间,如果空间不够考虑滚动数组优化。
剩下的转移从上面即可推出,复杂度 O(n2)O(n^2)

代码

CPP
constexpr int N(5e3+10);

int n,L,R;
struct node {
	int l,r;
	node(int l=0,int r=0):l(l),r(r) {}

	void Input() { scanf("%d%d",&l,&r),l=-l; }

	int len() { return r-l; }

	friend bool operator <(node a,node b) { return a.len()>b.len(); }
} a[N];
ll f[N>>1][2],_f[N>>1][2];

signed main() {
	/*DE("Input");*/
	scanf("%d",&n),L=(n-1)>>1,R=n>>1;
	FOR(i,1,n)a[i].Input();
	sort(a+1,a+n+1);
	/*DE("DP");*/
	FOR(l,0,(n+1)>>1)f[l][0]=f[l][1]=LINF;
	f[0][0]=0;
	FOR(i,1,n) {
		FOR(l,0,min(i,L))_f[l][0]=_f[l][1]=LINF;
		FOR(l,0,min(i-1,L)) {
			int r((i-1)-l);
			if(l<L)tomin(_f[l+1][0],f[l][0]+(ll)l*a[i].len()+a[i].r);
			if(r<R)tomin(_f[l][0],f[l][0]+(ll)r*a[i].len()-a[i].l);
			tomin(_f[l][1],f[l][0]+(ll)R*a[i].r-(ll)L*a[i].l);
		}
		FOR(l,0,min(i-2,L)) {
			int r((i-1)-l-1);
			if(l<L)tomin(_f[l+1][1],f[l][1]+(ll)l*a[i].len()+a[i].r);
			if(r<R)tomin(_f[l][1],f[l][1]+(ll)r*a[i].len()-a[i].l);
		}
		swap(f,_f);
	}
	/*DE("Output");*/
	printf("%lld\n",f[L][1]);
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...