B/b.cpp:表达式化简,二分答案
不知道能不能粘题面于是不粘了。
首先声明这道题可以怎么水过:
随机化几万次操作,取最优答案。
暴力O(n2log n)可过。
不想打正解的可以走了。
emm然而我的应该是正解,O(n log n)。
首先不难想到二分答案,判断最大距离是mid是否可行。
假设决策点是x,y。
那么对于所有的点对(p,q)有5种走法。
直接走。q-p;
其余情况都是走到x再跳到y再走到q。是abs(x-p)+abs(y-q)
拆开。
若p<x,y<q,是q-p-y+x
若p<x,y>q,是-p-q+y+x
若p>x,y<q,是p+q-x-y
若p>x,y>q,是p-q-x+y
而这些值都不能大于mid。
那么对于所有q-p>mid的点对,如果它满足那个带abs的式子,那么它一定同时满足这4个式子。
列成不等式组,其实就是A<=x+y<=B,C<=x-y<=D的形式
那么我们只要判定$B_{min}>=A_{max}$且$D_{min}>=C_{max}$即可。
推荐自己手推一下式子。
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 using namespace std; 5 int n,m,l[100005],r[100005]; 6 bool check(int x){ 7 int m00=-200000,m01=-200000,m10=-200000,m11=-200000; 8 for(int i=1;i<=m;++i)if(r[i]-l[i]>x)m00=max(m00,l[i]+r[i]),m01=max(m01,l[i]-r[i]), 9 m10=max(m10,r[i]-l[i]),m11=max(m11,-l[i]-r[i]); 10 return x-m11>=m00-x&&x-m10>=m01-x; 11 } 12 int main(){ 13 scanf("%d%d",&n,&m); 14 for(int i=1;i<=m;++i)scanf("%d%d",&l[i],&r[i]); 15 int ll=0,rr=n; 16 while(ll<rr-1)if(check(ll+rr>>1))rr=ll+rr>>1;else ll=(ll+rr>>1)+1; 17 if(check(ll))printf("%d\n",ll);else printf("%d\n",rr); 18 }
$Fate \ is \ Fake$