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;
}

浙公网安备 33010602011771号