题目 P2123 皇后游戏
思路:贪心(微扰/邻项交换)
微扰/邻项交换:证明在任意局面下,任何对局部最优解的微小改变都会造成整体结果变差,经常用于以“排序”为贪心策略的证明。
注意:排序的 > > > o r or or < < <必须满足严格弱序,传递性(即可以传递到整体而非局部相邻才满足此不等式)
建议参考这篇博客:传送门
设前一项为
i
i
i,后一项为
j
(
i
+
1
)
j(i+1)
j(i+1),设
C
i
−
1
C_{i-1}
Ci−1为
y
y
y,设
∑
j
=
1
i
−
1
\sum\limits_{j=1}^{i-1}
j=1∑i−1为
x
x
x
由上图可得:
交换前:
C
i
=
m
a
x
(
y
,
x
+
a
i
)
+
b
i
C_i=max(y,x+a_i)+b_i
Ci=max(y,x+ai)+bi
C
i
+
1
=
m
a
x
(
C
i
,
x
+
a
i
+
a
j
)
+
b
j
C_{i+1}=max(C_i,x+a_i+a_{j})+b_j
Ci+1=max(Ci,x+ai+aj)+bj
交换后:
C
i
=
m
a
x
(
y
,
x
+
a
j
)
+
b
j
C_i=max(y,x+a_j)+b_j
Ci=max(y,x+aj)+bj
C
i
+
1
=
m
a
x
(
C
i
,
x
+
a
i
+
a
j
)
+
b
i
C_{i+1}=max(C_i,x+a_i+a_{j})+b_i
Ci+1=max(Ci,x+ai+aj)+bi
则交换前:
C
i
+
1
=
m
a
x
{
y
+
b
i
+
b
i
+
1
,
x
+
a
i
+
b
i
+
b
i
+
1
,
x
+
a
i
+
a
i
+
1
+
b
i
+
1
}
C_{i+1}=max\{y+b_i+b_{i+1},x+a_i+b_i+b_{i+1},x+a_i+a_{i+1}+b_{i+1}\}
Ci+1=max{y+bi+bi+1,x+ai+bi+bi+1,x+ai+ai+1+bi+1}
⋯
\cdots
⋯
①
①
①
交换后:
C
i
+
1
=
m
a
x
{
y
+
b
i
+
b
i
+
1
,
x
+
a
i
+
1
+
b
i
+
b
i
+
1
,
x
+
a
i
+
a
i
+
1
+
b
i
}
C_{i+1}=max\{y+b_i+b_{i+1},x+a_{i+1}+b_i+b_{i+1},x+a_i+a_{i+1}+b_{i}\}
Ci+1=max{y+bi+bi+1,x+ai+1+bi+bi+1,x+ai+ai+1+bi}
⋯
\cdots
⋯
②
②
②
比较上面两式:发现都有一项为:
y
+
b
i
+
b
i
+
1
y+b_i+b_{i+1}
y+bi+bi+1,故舍掉 TAT不知道怎么证明,有证明麻烦dd
对
①
①
①进行化简:
C
i
+
1
=
x
+
a
i
+
b
i
+
1
+
m
a
x
{
b
i
,
a
i
+
1
}
C_{i+1}=x+a_i+b_{i+1}+max\{ b_i,a_{i+1}\}
Ci+1=x+ai+bi+1+max{bi,ai+1}
对
②
②
②进行化简:
C
i
+
1
=
x
+
a
i
+
1
+
b
i
+
m
a
x
{
b
i
+
1
,
a
i
}
C_{i+1}=x+a_{i+1}+b_{i}+max\{ b_{i+1},a_{i}\}
Ci+1=x+ai+1+bi+max{bi+1,ai}
假设不交换更优,则有
①
≤
②
①\le②
①≤②
移项化简得:
m
a
x
{
b
i
,
a
j
}
−
a
j
−
b
i
≤
m
a
x
{
b
j
,
a
i
}
−
a
i
−
b
j
max\{b_i,a_j\}-a_j-b_i\le max\{b_j,a_i\}-a_i-b_j
max{bi,aj}−aj−bi≤max{bj,ai}−ai−bj
相当于:
−
m
i
n
{
a
j
,
b
i
}
≤
−
m
i
n
{
a
i
,
b
j
}
-min\{a_j,b_i\}\le -min\{a_i,b_j\}
−min{aj,bi}≤−min{ai,bj}
即:
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\}
min{ai,bj}≤min{aj,bi}
⋯
③
\cdots③
⋯③
即假设不交换
(
i
(i
(i在
j
j
j前
)
)
)更优时满足
③
③
③,我们注意到,
③
③
③的符号是
≤
\le
≤,不满足非自反性,即不满足传递性,所以我们要分类讨论使其对任一情况均适用。
感觉luogu此人题解思路很妙
题解链接感谢大佬
latex写吐了,终于到了我们最爱的代码时间
#include <bits/stdc++.h>
#define int long long
using namespace std;
int t;
const int N=2e4+50;
inline int read(){
int cnt=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-') f=-f;c=getchar();}
while(isdigit(c)){cnt=(cnt<<3)+(cnt<<1)+(c^48);c=getchar();}
return cnt*f;
}
struct node{
int a,b,k;
bool operator <(node now) const{//重载运算符大法好!!!
if(k!=now.k) return k<now.k;
if(k<=0) return a<now.a;
return b>now.b;
}
}per[N];
signed main(){
t=read();
while(t--){
int n;n=read();
for(int i=1;i<=n;++i){
per[i].a=read();per[i].b=read();
if(per[i].a>per[i].b)
per[i].k=1;
else if(per[i].a<per[i].b)
per[i].k=-1;
else
per[i].k=0;
}
sort(per+1,per+1+n);
int s[N];memset(s,0,sizeof(s));
int ans=-0x3f3f;
for(int i=1;i<=n;i++){
s[i]=s[i-1]+per[i].a;
ans=max(ans,s[i])+per[i].b;
}
printf("%lld\n",ans);
}
return 0;
}
自己对邻项交换的理解:
- 根据题意推出公式,并按分析出的公式进行排序使其满足条件(传递性,非自反性
⋯
\cdots
⋯)
(分类讨论大法好),最后因为已经排序,直接计算第 n n n项即可。 - 如何排序:满足题意(最优解)的条件是对于任意 i , j i,j i,j都满足我们已经推出的公式,进行操作使任意 i , j i,j i,j都满足这个公式即可