CF1239E Turtle

CF1239E Turtle

有一个 \(2 \times n\) 的网格,第 \(i\) 行第 \(j\) 列的格子上的数为 \(a_{i,j}\)。一只乌龟从网格的左上角开始,每次可以向右或向下走一步,最终走到右下角。定义乌龟的得分为它经过的所有格子上的数之和。你需要重排所有的 \(a_{i,j}\),最小化乌龟可能得到的最大得分。

\(2 \leq n \leq 25\)\(0 \leq a_{i,j} \leq 50000\)

我们考虑当 \(a_{i,j}\) 的排列顺序固定时乌龟如何取得最大得分。不难发现乌龟只可能向下走一次,不妨设乌龟在第 \(x\) 列向下走一次,则乌龟的得分为 \(\sum\limits_{i=1}^{x} a_{1,i}+\sum\limits_{i=x}^{n} a_{2,i}\)。由这一个式子我们可以得出下面的结论:

  • 若第一行和第二行的数已经固定,则将第一行升序排列,第二行降序排列一定不劣。

证明显然,考虑升序排列得到的前缀和一定最小,降序排列得到的后缀和一定最小。根据这一点,我们可以发现新的性质:

  • 乌龟只有可能在第 \(1\) 列或第 \(n\) 列向下走。

证明考虑若乌龟在第 \(x\) 列向下走最优,其中 \(1 < x < n\),我们考察 \(a_{1,x}\)\(a_{1,x+1}\)\(a_{2,x-1}\)\(a_{2,x}\)。由上面的性质可知 \(a_{1,x+1} \geq a_{1,x}\)\(a_{2,x-1} \geq a_{2,x}\)。又由于乌龟在第 \(x\) 列向下走最优,所以 \(a_{1,x} \geq a_{2,x-1}\)\(a_{2,x} \geq a_{1,x+1}\)。由上面的式子推知 \(a_{1,x}=a_{1,x+1}=a_{2,x-1}=a_{2,x}\),进而可以得到在第 \(x-1\) 列向下走,在第 \(x+1\) 列向下走也是最优的,进而可以得到在每一列向下走都是最优的,此时乌龟可以在第 \(1\) 列向下走或在第 \(n\) 列向下走,即证。

接下来你只需要最小化 \(\max(\sum\limits_{i=1}^{n} a_{1,i}+a_{2,n},\sum\limits_{i=1}^{n} a_{2,i}+a_{1,1})\) 即可。容易发现在此时的式子中,\(a_{1,1}\)\(a_{2,n}\) 应该取到 \(\{a_{i,j}\}\) 中的最小值与次小值。接下来就可以扣掉这两个数,只需要将剩下的数划分为两个元素个数相同的集合即可,于是就可以 dp 了。

时间复杂度 \(O(n^2 \sum a_i)\),为了省事我的代码复杂度是 \(O(n^3V)\) 的。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int V=1200000;
int a[60],ans[3][30];
bool ok[25][V+10];
int come[25][V+10];
bool vis[60];
int main(){
	int n;
	scanf("%d",&n);
	for(int i=1;i<=2*n;i++){
		scanf("%d",&a[i]);
	}
	sort(a+1,a+2*n+1);
	ans[1][1]=a[1];
	ans[2][n]=a[2];
	int sum=0;
	ok[0][0]=true;
	for(int i=3;i<=2*n;i++){
		sum+=a[i];
		for(int j=n-1;j>=1;j--){
			for(int k=a[i];k<=V;k++){
				if(!ok[j][k]  &&  ok[j-1][k-a[i]]){
					ok[j][k]=true;
					come[j][k]=i;
				}
			}
		}
	}
	for(int i=sum/2;i>=0;i--){
		if(ok[n-1][i]){
			int tmp=i;
			for(int j=n;j>=2;j--){
				ans[1][j]=a[come[j-1][tmp]];
				vis[come[j-1][tmp]]=true;
				tmp-=a[come[j-1][tmp]];
			}
			break;
		}
	}
	int pre=0; 
	for(int i=2*n;i>=3;i--){
		if(!vis[i]){
			ans[2][++pre]=a[i];
		}
	}
	for(int i=1;i<=2;i++){
		for(int j=1;j<=n;j++){
			printf("%d ",ans[i][j]);
		}
		printf("\n");
	}
	return 0;
}
posted @ 2025-10-27 12:26  Oken喵~  阅读(4)  评论(0)    收藏  举报