[Codeforces1239E]Turtle

题意

给你一个 2 × n 2\times n 2×n的棋盘,经过格子 ( i , j ) (i,j) (i,j)就会获得权值 a i , j a_{i,j} ai,j

重新排列整个棋盘,使得从左上角走到右下角的路径权值和的最大值最小(只能向下或者向右走)

2 ≤ n ≤ 25 , 0 ≤ a i , j ≤ 5 × 1 0 4 ( 1 ≤ i ≤ 2 , 1 ≤ j ≤ n ) 2\le n\le25,0\le a_{i,j}\le5\times10^4(1\le i\le2,1\le j\le n) 2n25,0ai,j5×104(1i2,1jn)


题解

考虑交换同一行两个数的位置对最大值的影响
在这里插入图片描述
变成
在这里插入图片描述
那么有的路径权值和不会改变,有的路径取值和会减小,这样路径最大值就有可能减小

所以第一行升序排序更优,同理可得第二行降序排列更优

考虑对于一种已经排好序的棋盘答案多少

考虑两个相邻路径的权值和的差异

x 1 x_1 x1 x i x_i xi x i + 1 x_{i+1} xi+1 x n x_n xn
y 1 y_1 y1 y i y_i yi y i + 1 y_{i+1} yi+1 y n y_n yn

对于路径 x 1 → . . . → x i → y i → . . . → y n x_1\rightarrow...\rightarrow x_i\rightarrow y_i\rightarrow...\rightarrow y_n x1...xiyi...yn和路径 x 1 → . . . → x i → x i + 1 → y i + 1 → . . . → y n x_1\rightarrow...\rightarrow x_i\rightarrow x_{i+1}\rightarrow y_{i+1}\rightarrow...\rightarrow y_n x1...xixi+1yi+1...yn

他们的权值差的绝对值就是 Δ i = ∣ x i + 1 − y i ∣ \Delta_i=|x_{i+1}-y_i| Δi=xi+1yi,由于 x x x递增, y y y递减

所以 Δ i \Delta_i Δi的函数图像就长这样在这里插入图片描述

所以最大值就一定会在两边取到,即最大值为 max ⁡ ( ∑ i = 1 n x i + y n , x 1 + ∑ i = 1 n y i ) = x 1 + y n + max ⁡ ( ∑ i = 2 n x i , ∑ i = 1 n − 1 y i ) \max(\sum_{i=1}^nx_i+y_n,x_1+\sum_{i=1}^ny_i)=x_1+y_n+\max(\sum_{i=2}^nx_i,\sum_{i=1}^{n-1}y_i) max(i=1nxi+yn,x1+i=1nyi)=x1+yn+max(i=2nxi,i=1n1yi)

把最小的两个数拿走,问题就转化成了:给你一个有 m m m个数的序列 a a a,将其分成两个等大的集合 A , B A,B A,B,最小化 max ⁡ ( ∑ A , ∑ B ) \max(\sum A,\sum B) max(A,B)

这个问题实质上就是一个背包问题

先把 a a a从小到大排序,设 S u m = ∑ a Sum=\sum a Sum=a

f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示前 i i i个数中放 j j j个数在集合 A A A中,且 ∑ A = k \sum A=k A=k的情况是否存在

那么 f [ i ] [ j ] [ k ] = f [ i − 1 ] [ j ] [ k ] ∣ f [ i − 1 ] [ j − 1 ] [ k − a i ] f[i][j][k]=f[i-1][j][k]|f[i-1][j-1][k-a_i] f[i][j][k]=f[i1][j][k]f[i1][j1][kai]

那么 A n s = min ⁡ { max ⁡ ( k , S u m − k ) } Ans=\min\{\max(k,Sum-k)\} Ans=min{max(k,Sumk)},可见 A n s Ans Ans越靠近 S u m 2 \frac{Sum}2 2Sum越小

然后根据 A n s Ans Ans寻找转移路径输出答案即可

一个小优化是 f f f的转移可以用 C + + C++ C++ b i t s e t bitset bitset实现

时间复杂度 O ( 1 64 n 2 ∑ a ) O(\frac1{64}n^2\sum a) O(641n2a)

#include<bits/stdc++.h>
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
using namespace std;
const int N=55,M=50*5e4+5;
typedef long long ll;
int n,m;
bitset<M>f[52][26];
int main(){
	#ifndef ONLINE_JUDGE
		file("s");
	#endif
	scanf("%d",&n);m=(--n)<<1;
	vector<int>a(m+3),Ans[2];
	fp(i,1,m+2)scanf("%d",&a[i]);
	sort(a.begin()+1,a.end());
	Ans[0].push_back(a[1]);a.erase(a.begin()+1);
	Ans[1].push_back(a[1]);a.erase(a.begin()+1);
	f[0][0][0]=1;
	fp(i,1,m){
		f[i][0][0]=1;
		fp(j,1,min(n,i))
			f[i][j]=f[i-1][j]|(f[i-1][j-1]<<a[i]);
	}
	int Cur=accumulate(a.begin()+1,a.end(),0)>>1,Cnt=n;
	while(!f[m][n][Cur])--Cur;
	fd(i,m,1)
		if(a[i]>Cur||!f[i-1][Cnt-1][Cur-a[i]])
			Ans[0].push_back(a[i]);
		else Ans[1].push_back(a[i]),Cur-=a[i],--Cnt;
	sort(Ans[0].begin(),Ans[0].end());
	sort(Ans[1].begin(),Ans[1].end(),greater<int>());
	fp(i,0,1)fp(j,0,n)printf("%d%c",Ans[i][j]," \n"[j==n]);
return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值