首页 > 其他分享 >P2123 皇后游戏 / [USACO12JAN] Mountain Climbing S / P1248 加工生产调度 题解

P2123 皇后游戏 / [USACO12JAN] Mountain Climbing S / P1248 加工生产调度 题解

时间:2024-11-10 19:57:40浏览次数:1  
标签:Mountain aligned res mathit P1248 题解 int max 排序

P2123 皇后游戏 / [USACO12JAN] Mountain Climbing S / P1248 加工生产调度

先来看 P2123。我们把这个特别重要的公式打出来:

\[c_{i} = \begin{cases} a_{1}+b_{1} & ,i=1 \\ \displaystyle \max \left \{ c_{i-1},\sum_{j=1}^{i}a_{j} \right \} +b_{i} & ,2\leq i \leq n \end{cases} \]

有了国王游戏的经验,我们尝试找到一个通用的排序公式。

发现本题中的 \(c_i\) 应该是递增的,也就是 \(c_{i+1}\ge c_i\)。

设当前位置为 \(i\),\(\sum_{k=1}^{i-1}a_k\) 为 \(x\),上一位的答案为 \(m\),令 \(i+1=j\)。则:

\[\begin{aligned} \mathit{res}_1&=\max(\max(m,x+a_i)+b_i,x+a_i+a_j)+b_j~;\\ \mathit{res}_2&=\max(\max(m,x+a_j)+b_j,x+a_j+a_i)+b_i~. \end{aligned} \]

化为:

\[\begin{aligned} \mathit{res}_1&=\max(m+b_i,x+a_i+b_i,x+a_i+a_j)+b_j~;\\ \mathit{res}_2&=\max(m+b_i,x+a_j+b_j,x+a_i+a_j)+b_i~. \end{aligned} \]

遇到瓶颈。但是我们可以证明,\(m+b_i\) 可以消去。具体就不证了,前人之述备矣。消去 \(m+b_i\),再消去 \(x\),化为:

\[\begin{aligned} \mathit{res}_1&=\max(a_i+b_i,a_i+a_j)+b_j~;\\ \mathit{res}_2&=\max(a_j+b_j,a_i+a_j)+b_i~. \end{aligned} \]

提出 \(a_i\)、\(a_j\):

\[\begin{aligned} \mathit{res}_1&=\max(b_i,a_j)+a_i+b_j~;\\ \mathit{res}_2&=\max(b_j,a_i)+a_j+b_i~. \end{aligned} \]

若不交换更优,即 \(\mathit{res}_1<\mathit{res}_2\),则:

\[\max(b_i,a_j)+a_i+b_j<\max(b_j,a_i)+a_j+b_i~. \]

移项,得:

\[\max(b_i,a_j)-a_j-b_i<\max(b_j,a_i)-a_i-b_j~. \]

稍微想想,就能得到:

\[-\min(b_i,a_j)<-\min(b_j,a_i)~. \]

即:

\[\min(b_i,a_j)>\min(b_j,a_i)~. \]

酣畅淋漓。

这个不等式实际上就是 Johnson 不等式,用于解决流水调度问题

#include<bits/stdc++.h>
#define fw fwrite(obuf,p3-obuf,1,stdout)
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
#define putchar(x) (p3-obuf<1<<20?(*p3++=(x)):(fw,p3=obuf,*p3++=(x)))
using namespace std;

char buf[1<<20],obuf[1<<20],*p1=buf,*p2=buf,*p3=obuf,str[20<<2];
int read(){
	int x=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x;
}
template<typename T>
void write(T x,char sf='\n'){
	if(x<0)putchar('-'),x=~x+1;
	int top=0;
	do str[top++]=x%10,x/=10;while(x);
	while(top)putchar(str[--top]+48);
	if(sf^'#')putchar(sf);
}
using ll=long long;
constexpr int MAXN=2e4+5;
int T,n;
int min(int a,int b){
	return a<b?a:b;
}
ll max(ll a,ll b){
	return a>b?a:b;
}
struct P{
	int a,b;
	bool operator<(const P&x)const{
		return min(b,x.a)>min(x.b,a);
	}
}p[MAXN];

int main(){
	T=read();
	while(T--){
		n=read();
		for(int i=1;i<=n;++i) p[i]={read(),read()};
		sort(p+1,p+n+1);
		ll res=p[1].a+p[1].b,sm=p[1].a,lst=res;
		for(int i=2;i<=n;++i){
			sm+=p[i].a;
			res=max(res,lst=max(lst,sm)+p[i].b);
		}
		write(res);
	}
	return fw,0;
}

你是不是以为这样就 AC 了?然后你就会发现你得到了高贵的 80pts。

伪在哪里?伪在排序的不稳定性。你会发现上述的排序方法会漏掉很多情况,不能准确地排序。比如,最基本的传递性都不能保证。

排序的传递性:若 \(a<b\land b<c\),则 \(a<c\)。

此时有两种解决方法:

  1. 掺点随机化,在时间允许的范围内多排序几次。
  2. 想办法完善刚才的排序式子。

方法 1 虽好,但也让我们和最优解失之交臂。我们还是来看方法 2。

回顾刚才的排序式子:

\[\min(b_i,a_j)>\min(b_j,a_i)~. \]

要使一个数排在前面,则 \(a\) 越小越好,\(b\) 越大越好。这句话不是我说的,是题解说的。

我们把所有数对分成三大组:

  1. 当 \(a_i<b_i\land a_j<b_j\) 时,则 \(a_i\le a_j\),应该按 \(a\) 升序排序;
  2. 当 \(a_i=b_i\land a_j=b_j\) 时,随便排;
  3. 当 \(a_i>b_i\land a_j>b_j\) 时,则 \(b_i\ge b_j\),应该按 \(b\) 降序排序。

然后考虑这三大组之间的排序关系。发现 1 组在前、2 组在中、3 组在右的原则是能保证答案的,于是令

\[d_i=\begin{cases}1&a_i>a_j\\0&a_i=a_j\\-1&a_i<a_j\end{cases}~,\quad\text{即 }d_i=\operatorname{sgn}(a_i-a_j)~. \]

由此得到最终的排序条件:先按 \(d\) 值排序,然后若 \(d\le0\),把 \(a\) 升序排序(这里将 2 组归为 1 组);否则把 \(b\) 降序排序。

完美。

#include<bits/stdc++.h>
#define fw fwrite(obuf,p3-obuf,1,stdout)
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
#define putchar(x) (p3-obuf<1<<20?(*p3++=(x)):(fw,p3=obuf,*p3++=(x)))
using namespace std;

char buf[1<<20],obuf[1<<20],*p1=buf,*p2=buf,*p3=obuf,str[20<<2];
int read(){
	int x=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x;
}
template<typename T>
void write(T x,char sf='\n'){
	if(x<0)putchar('-'),x=~x+1;
	int top=0;
	do str[top++]=x%10,x/=10;while(x);
	while(top)putchar(str[--top]+48);
	if(sf^'#')putchar(sf);
}
using ll=long long;
constexpr int MAXN=2e4+5;
int T,n;
int min(int a,int b){
	return a<b?a:b;
}
ll max(ll a,ll b){
	return a>b?a:b;
}
struct P{
	int a,b,d;
	bool operator<(const P&x)const{
		if(d^x.d) return d<x.d;
		if(d^1) return a<x.a;
		return b>x.b;
	}
}p[MAXN];

int main(){
	T=read();
	while(T--){
		n=read();
		for(int i=1;i<=n;++i){
			p[i]={read(),read()};
			p[i].d=p[i].a>p[i].b?1:p[i].a<p[i].b?-1:0;
		}
		sort(p+1,p+n+1);
		ll res=p[1].a+p[1].b,sm=p[1].a,lst=res;
		for(int i=2;i<=n;++i){
			sm+=p[i].a;
			res=max(res,lst=max(lst,sm)+p[i].b);
		}
		write(res);
	}
	return fw,0;
}

至于剩下的两道题,完全可以看作本题的三倍经验。因为 Johnson 不等式本就是用于解决流水调度问题,这两道题反而更加简单。

对于 USACO 的那道题,显然总耗时由以下两个因素决定:还未上山的奶牛需要上山,以及上了山的奶牛需要下山。我们的目标是让山上等待下山的奶牛序列不间断,这样就节省了时间,故上山快的奶牛需要先上山。同理,为了让下山序列连续,下山慢的奶牛需要先下山。然后就会发现和上文推出的 Johnson 不等式是一样的。

对于 P1248 更是同理。

标签:Mountain,aligned,res,mathit,P1248,题解,int,max,排序
From: https://www.cnblogs.com/laoshan-plus/p/18538380

相关文章

  • 历年CSP-J初赛真题解析 | 2019年CSP-J初赛完善程序(34-43)
    学习C++从娃娃抓起!记录下CSP-J备考学习过程中的题目,记录每一个瞬间。附上汇总贴:历年CSP-J初赛真题解析|汇总_热爱编程的通信人的博客-CSDN博客矩阵变幻有一个奇幻的矩阵,在不停的变幻,其变幻方式为:数字0变成矩阵[......
  • [NOIP2012 提高组] 国王游戏 题解
    [NOIP2012提高组]国王游戏典贪心。设当前点为\(i\),\(\prod_{k=0}^{i-1}a_k\)为\(x\),则对于\(i,j\)两点的答案:(为了方便,记\(i+1=j\))\[\mathit{res}_1=\max\bigg(\dfracx{b_i},\dfrac{xa_i}{b_j}\bigg)~;\]若交换,则:\[\mathit{res}_2=\max\bigg(\dfracx{b_j},\dfrac{......
  • [luogu1248] 加工生产调度 题解
    考虑\(i\)排在\(j\)前的条件是\(a_i+\max(a_j,b_i)+b_j\lea_j+\max(a_i,b_j)+b_i\),然后发现这一坨东西是皇后游戏中的倒数第三个式子,直接转化为\(\min(a_j,b_i)\ge\min(a_i,b_j)\),然后就按皇后游戏中的排序方法就可以了……#include<bits/stdc++.h>#defineintlonglong......
  • [luogu1248] 加工生产调度 题解
    考虑\(i\)排在\(j\)前的条件是\(a_i+\max(a_j,b_i)+b_j\lea_j+\max(a_i,b_j)+b_i\),然后发现这一坨东西是皇后游戏中的倒数第三个式子,直接转化为\(\min(a_j,b_i)\ge\min(a_i,b_j)\),然后就按皇后游戏中的排序方法就可以了……#include<bits/stdc++.h>#defineintlonglong......
  • [luogu1248] 加工生产调度 题解
    考虑\(i\)排在\(j\)前的条件是\(a_i+\max(a_j,b_i)+b_j\lea_j+\max(a_i,b_j)+b_i\),然后发现这一坨东西是皇后游戏中的倒数第三个式子,直接转化为\(\min(a_j,b_i)\ge\min(a_i,b_j)\),然后就按皇后游戏中的排序方法就可以了……#include<bits/stdc++.h>#defineintlonglong......
  • CCPC 网络赛题解(D/I/J)
    D根据题目给出的构造方式,\(S_n'\)的长度会达到\(2^n\)数量级,没法求出\(S_n'\),所以考虑递推。设\(dp_{i,l,r}\)为\(S_i'\)里\(T\)的\([l,r]\)区间以子序列的方式出现了多少次,可以写出转移方程:\(dp_{i,l,r}=\sumdp_{i-1,l,k}\cdotdp_{i-1,k+1,r}+[a_i=T_k]\cdot......
  • [JXOI2017] 加法 题解
    最小值最大,考虑二分答案,问题转为判断最小值是否能\(\gex\)。假如\(a_i\gex\),那我们肯定不管;假如\(a_i<x\),那最好能让选择的区间\(r\)值更大,用优先队列维护即可。区间增幅可以用树状数组维护。时间复杂度\(O(n\log^2n)\)。#include<bits/stdc++.h>#defineintlonglon......
  • [CF1981E] Turtle and Intersected Segments 题解
    好题好题。难点在建图,因为图的边数将会决定最小生成树的时间复杂度。我们肯定希望能够只建\(O(n)\)级别的边,这样时间复杂度就可以做到\(O(n\logn)\)。观察到当\(i,j,k\)三个区间能够互相连边时(这里假设\(a_i<a_j<a_k\)),我们绝对不会连\((i,k)\)这条边。那么假如我们将......
  • [CF1981E] Turtle and Intersected Segments 题解
    好题好题。难点在建图,因为图的边数将会决定最小生成树的时间复杂度。我们肯定希望能够只建\(O(n)\)级别的边,这样时间复杂度就可以做到\(O(n\logn)\)。观察到当\(i,j,k\)三个区间能够互相连边时(这里假设\(a_i<a_j<a_k\)),我们绝对不会连\((i,k)\)这条边。那么假如我们将......
  • ABC379E 题解
    ABC379E题解一道很好的题,开始还以为是高精度来着,但是发现不必要也不能用高精度,而是用一种技巧代替。题意Youaregivenastring\(S\)oflength\(N\)consistingofdigitsfrom1through9.Foreachpairofintegers\((i,j)\(1\leqi\leqj\leqN)\),define\(f(......