皇后游戏解析

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/wljoi/article/details/102575788

前言

由于笔者自认为网上有些题解显得不够清晰或严谨,故撰此文,来介绍另一种解法。

正题

传送门

解析:题目要求的是这样一个式子中 c [ i ] c[i] 的最大值的最小值:

由于 a i , b i a_i,b_i 均为正数,所以 c i c_i 一定是递增的,故我们要求的即为 c n c_n 的最小值。

我们有一个结论:对于两位大臣 ( a i , b i ) , ( a j , b j ) (a_i,b_i),(a_j,b_j) ,如果 m i n ( a i , b j ) m i n ( a j , b i ) min(a_i,b_j)\le min(a_j,b_i) ,那么我们将 ( a i , b i ) (a_i,b_i) 放在前面更优,证明如下( 2014 2014 年北京市高考理科数学第 20 20 题第 2 2 问):

c 1 = a 1 + b 1 c_1=a_1+b_1
c 2 = m a x ( c 1 , a 1 + a 2 ) + b 1 = m a x ( a 1 + b 1 , a 1 + a 2 ) + b 2 c_2=max(c_1,a_1+a_2)+b_1=max(a_1+b_1,a_1+a_2)+b_2
c 2 = m a x ( a 1 + b 1 + b 2 , a 1 + a 2 + b 2 ) c_2=max(a_1+b_1+b_2,a_1+a_2+b_2)
c 3 = m a x ( c 2 , a 1 + a 2 + a 3 ) + b 3 c_3=max(c_2,a_1+a_2+a_3)+b_3
c 3 = m a x ( a 1 + b 1 + b 2 , a 1 + a 2 + b 2 , a 1 + a 2 + a 3 ) + b 3 c_3=max(a_1+b_1+b_2,a_1+a_2+b_2,a_1+a_2+a_3)+b_3
c 3 = m a x ( a 1 + b 1 + b 2 + b 3 , a 1 + a 2 + b 2 + b 3 , a 1 + a 2 + a 3 + b 3 ) c_3=max(a_1+b_1+b_2+b_3,a_1+a_2+b_2+b_3,a_1+a_2+a_3+b_3)
综上,我们可以发现一个规律:

我们记 S n ( k ) S_n(k) i = 1 k a i + i = k n b i \sum_{i=1}^ka_i+\sum_{i=k}^nb_i

那么 c i = m a x ( S i ( 1 ) , S i ( 2 ) , S i ( 3 ) , . . . , S i ( i ) ) c_i=max(S_i(1),S_i(2),S_i(3),...,S_i(i))

但这只是我们找出来的规律,下面给出严谨证明:

我们考虑用一个 2 n 2*n 的矩阵来表示我们的序列 ( a 1 , b 1 ) , ( a 2 , b 2 ) , . . . , ( a n , b n ) (a_1,b_1),(a_2,b_2),...,(a_n,b_n)

c 3 c_3 为例,我们来画出这些走法,它们分别对应所有的 S S

[ a 1 a 2 a 3 b 1 b 2 b 3 ] \begin{bmatrix} a_1 && a_2 &&a_3 \\↓\\ b_1 &→& b_2&→ &b_3 \end{bmatrix}\\
[ a 1 a 2 a 3 b 1 b 2 b 3 ] \begin{bmatrix} a_1 &→& a_2 &&a_3 \\&&↓\\ b_1 && b_2&→ &b_3 \end{bmatrix}\\
[ a 1 a 2 a 3 b 1 b 2 b 3 ] \begin{bmatrix} a_1 &→& a_2 &→&a_3 \\&&&&↓\\ b_1 && b_2& &b_3 \end{bmatrix}\\
所以 c n c_n 在我们的矩阵里表示从 a 1 a_1 b n b_n n n 条路径中 n + 1 n+1 个数字和的最大值。

我们用数学归纳法证明 c i = m a x ( S i ( 1 ) , S i ( 2 ) , S i ( 3 ) , . . . , S i ( i ) ) c_i=max(S_i(1),S_i(2),S_i(3),...,S_i(i))

n = 1 n=1 时, c 1 = m a x ( S 1 ( 1 ) ) c_1=max(S_1(1)) ,显然成立。

假设当 n = k ( k 1 ) n=k(k\ge1) 时,命题成立,即 c k = m a x ( S k ( 1 ) , S k ( 2 ) , S k ( 3 ) , . . . , S k ( k ) ) c_k=max(S_k(1),S_k(2),S_k(3),...,S_k(k))

那么当 n = k + 1 n=k+1 时,

c k + 1 = m a x ( c k , a 1 + a 2 + . . . + a k + 1 ) + b k + 1 c_{k+1}=max(c_k,a_1+a_2+...+a_{k+1})+b_{k+1}
b k + 1 b_{k+1} 带入 m a x max
c k + 1 = m a x ( c k + b k + 1 , a 1 + a 2 + . . . + a k + 1 + b k + 1 ) c_{k+1}=max(c_k+b_{k+1},a_1+a_2+...+a_{k+1}+b_{k+1})
合并后面的项
c k + 1 = m a x ( c k + b k + 1 , S k + 1 ( k + 1 ) ) c_{k+1}=max(c_k+b_{k+1},S_{k+1}(k+1))
c k c_k 拆开
c k + 1 = m a x ( S k ( 1 ) + b k + 1 , S k ( 2 ) + b k + 1 , . . . , S k ( k ) + b k + 1 , S k + 1 ( k + 1 ) ) c_{k+1}=max(S_k(1)+b_{k+1},S_k(2)+b_{k+1},...,S_k(k)+b_{k+1},S_{k+1}(k+1))
按照 S S 的定义合并所有项
c k + 1 = m a x ( S k + 1 ( 1 ) , S k + 1 ( 2 ) , . . . , S k + 1 ( k + 1 ) ) c_{k+1}=max(S_{k+1}(1),S_{k+1}(2),...,S_{k+1}(k+1))
原命题得证。

下一步,我们来证明如果 m i n ( a i , b j ) m i n ( a j , b i ) min(a_i,b_j)\le min(a_j,b_i) ,那么我们将 ( a i , b i ) (a_i,b_i) 放在前面更优。

考虑上文提到的矩阵,我们对于一个矩阵
[ a 1 a 2 a 3 . . . a n b 1 b 2 b 3 . . . b n ] \begin{bmatrix} a_1 & a_2 &a_3 &...&a_n\\\\ b_1 & b_2&b_3&...&b_n \end{bmatrix}\\
我们如果调换两人的顺序,也就是调换矩阵中两列的顺序。

我们假设调换第 k k 列和第 k + 1 k+1 列,我们得到一个新矩阵

[ a 1 a 2 a 3 . . . a n b 1 b 2 b 3 . . . b n ] \begin{bmatrix} a_1' & a_2' &a_3' &...&a_n'\\\\ b_1' & b_2'&b_3'&...&b_n' \end{bmatrix}\\
其中
[ a i b i ] = [ a i b i ] ( 1 i n i k , i k + 1 ) \begin{bmatrix} a_i \\\\ b_i \end{bmatrix}=\begin{bmatrix} a_i' \\\\ b_i' \end{bmatrix}\quad(1\le i\le n且i≠k,i≠k+1)
[ a k b k ] = [ a k + 1 b k + 1 ] \begin{bmatrix} a_k \\\\ b_k \end{bmatrix}=\begin{bmatrix} a_{k+1}' \\\\ b_{k+1}' \end{bmatrix}\quad
[ a k + 1 b k + 1 ] = [ a k b k ] \begin{bmatrix} a_{k+1} \\\\ b_{k+1} \end{bmatrix}=\begin{bmatrix} a_{k}' \\\\ b_{k}' \end{bmatrix}\quad
我们记 S n ( k ) S_n'(k) i = 1 k a i + i = k n b i , c n = m a x ( S n ( 1 ) , S n ( 2 ) , . . . , S n ( n ) ) \sum_{i=1}^ka_i'+\sum_{i=k}^nb_i',c'_n=max(S_n'(1),S_n'(2),...,S_n'(n))

我们设 σ = S n ( k 1 ) = S n ( k 1 ) = i = 1 k 1 a i + i = k + 2 n b i = i = 1 k 1 a i + i = k + 2 n b i \sigma=S_n(k-1)=S_n'(k-1)=\sum_{i=1}^{k-1}a_i+\sum_{i=k+2}^{n}b_i=\sum_{i=1}^{k-1}a_i'+\sum_{i=k+2}^{n}b_i' ,那么我们有:

S n ( k ) = σ + a k + b k + b k + 1 S_n(k)=\sigma+a_k+b_k+b_{k+1}
S n ( k + 1 ) = σ + a k + a k + 1 + b k + 1 S_n(k+1)=\sigma+a_k+a_{k+1}+b_{k+1}
S n ( k ) = σ + a k + b k + b k + 1 = σ + a k + 1 + b k + 1 + b k S_n'(k)=\sigma+a_k'+b_k'+b_{k+1}'=\sigma+a_{k+1}+b_{k+1}+b_k
S n ( k + 1 ) = σ + a k + a k + 1 + b k + 1 = σ + a k + 1 + a k + b k S_n'(k+1)=\sigma+a_k'+a_{k+1}'+b_{k+1}'=\sigma+a_{k+1}+a_k+b_k
m = m i n ( a k , a k + 1 , b k , b k + 1 ) , M = m a x ( S n ( k ) , S n ( k + 1 ) , S n ( k ) , S n ( k + 1 ) ) m=min(a_k,a_{k+1},b_k,b_{k+1}),M=max(S_n(k),S_n(k+1),S_n'(k),S_n'(k+1))

我们分别讨论 m m 的取值,

m = a k m=a_k 时,依照上文推出的 S , S S,S' 的表达式, M = S n ( k ) M=S_n'(k) ,所以 m a x ( S n ( k ) , S n ( k + 1 ) ) m a x ( S n ( k ) , S n ( k + 1 ) ) max(S'_n(k),S_n'(k+1))\ge max(S_n(k),S_n(k+1)) ,即 c n c n c_n'\ge c_n

其余三种情况同理。

最后我们得出当 m = a k b k + 1 m=a_k或b_{k+1} 时, c n c n c_n\le c_n' ,所以不应交换。

m = a k + 1 b k m=a_{k+1}或b_k 时, c n c n c_n\ge c_n' ,此时应交换 k k + 1 k与k+1 两列。

相邻两数间的情况可以方便的推广到任意两数交换的情况。

证毕。

从得到的式子 m i n ( a i , b j ) m i n ( a j , b i ) min(a_i,b_j)\le min(a_j,b_i) 可以看出,我们只需按这个条件排序后模拟即可。

但是,我们这样做是不严谨的。考虑这样一组数据,

7 3
1 1
1 6

显然满足上式,答案输出是 17 17

但是我们可以换一种排列方式也满足上式,

1 1
1 6
7 3

此时显然也满足,且答案为 12 12

为什么会出现这种情况呢?

原因就是这个式子不满足传递性,交换一次这样的式子对后面确实不会产生什么影响,但如果多交换几次答案可能就会变。

我们考虑对于一些数,如果某一组数排在前面,那么其 a i a_i 必定越小越好,其 b i b_i 必定越大越好。

我们按照 a b a与b 的大小关系将其分为 3 3 组:
{ a i < b i , a j < b j , a a i = b i , a j = b j , 1 a i > b i , a j > b j , a \left\{ \begin{aligned} a_i<b_i,a_j<b_j,按a升序排序 \qquad①\\ a_i=b_i,a_j=b_j,归入情况1中\qquad②\\ a_i>b_i,a_j>b_j,按a降序排序\qquad③\\ \end{aligned} \right.

由于题目中描述的式子是 c i = m a x ( c i 1 , i = 1 j a j ) + b i c_i=max(c_{i-1},\sum_{i=1}^j a_j)+b_i ,所以按照贪心的思路,我们先分情况在块内排序,再按照 ①②③ 的顺序排序,之后模拟即可。

#include<bits/stdc++.h>
#define int long long
using namespace std;
struct Node{
	int a,b,d;
}f[50005];
int c[50005];
bool cmp(Node x,Node y){
	if(x.d!=y.d)  return x.d<y.d;
	if(x.d<=0)  return x.a<y.a;
	return x.b>y.b;
}
signed main(){
	int T;
	scanf("%lld",&T);
	while(T--){
		int n;
		scanf("%lld",&n);
		for(int i=1;i<=n;i++){
			scanf("%lld%lld",&f[i].a,&f[i].b);
			if(f[i].a>f[i].b)  f[i].d=1;
			if(f[i].a==f[i].b)  f[i].d=0;
			if(f[i].a<f[i].b)  f[i].d=-1;
		}
		sort(f+1,f+n+1,cmp);
		int s=0;
		for(int i=1;i<=n;i++){
			s+=f[i].a;
			c[i]=max(c[i-1],s)+f[i].b;
		}
		cout<<c[n]<<endl;
	}
}

猜你喜欢

转载自blog.csdn.net/wljoi/article/details/102575788