P10025题解
P10025 「HCOI-R1」孤独的 sxz
题解
这个真的是 div2 的 T2 吗?
分享一下个人解法,不保证是最简洁的但不需要离散化或权值线段树。注意到这个题不按常理出牌,求的是最大曼哈顿距离,所以如果没有“不能和其他人坐在同一个地方”这个限制那么答案一定是四个角的其中一个。
小小证明一下:分开考虑 \(x,y\),这里以 \(x\) 为例,向上一格的收益是第一维比当前 \(x\) 大的人数减去剩下的,向下同理,假设向上更优,那么继续向上一定依然更优,因为第一维比当前 \(x\) 大的人数单调不减,剩下的人数单调不增,故到达边界一定更优。
那有了限制之后怎么做呢?沿用上面的证明,注意到答案一定在四个角的 \(k\times k\) 等腰直角三角形中。两个维度是独立的,故分开考虑,使用双指针或 map 不难处理出这 \(O(k)\) 行、列的独立贡献。
接下来,以左上角的三角形为例:我们先把 \((1,1)\) 的贡献扔进优先队列,每次取出贡献最大的点,如果不被占用则更新答案并退出,否则把可能成为答案的 \((i,j+1)\) 和 \((i+1,j)\) 扔进优先队列,这也算是堆的经典应用了。
容易发现我们最多只会循环 \(k\) 次,故复杂度 \(O(k\log k)\)。
旋转坐标轴,重复 \(4\) 次即可。
代码:
#include<bits/stdc++.h>
using namespace std;
inline int rd() {
int s=0,m=0;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-')m=1;ch=getchar();}
while( isdigit(ch)) s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
return m?-s:s;
}
int n,m,k;
map<pair<int,int>,int>mp,vis;
int mpx[400005],mpy[400005];
struct QWQ {int x,y;} a[400005],aaa[400005];
long long sx[400005],sy[400005],Ans;
struct qwq {
int x,y;long long p;
bool operator<(const qwq& r)const {return p<r.p;}
};
priority_queue<qwq> pq;
void solve() {
while(pq.size()) pq.pop();
memset(sx,0,sizeof(sx));
memset(sy,0,sizeof(sy));
memset(mpx,0,sizeof(mpx));
memset(mpy,0,sizeof(mpy));
mp.clear();vis.clear();
int ln=min(k+2,n),lm=min(k+2,m);
for(int i=1;i<=k;i++) {
if(a[i].x<=ln&&a[i].y<=lm)
mp[make_pair(a[i].x,a[i].y)]=1;
if(a[i].x<=ln) mpx[a[i].x]++;
if(a[i].y<=lm) mpy[a[i].y]++;
sx[1]+=a[i].x-1,sy[1]+=a[i].y-1;
}
for(int i=2,s=mpx[1];i<=ln;i++)
sx[i]=sx[i-1]+s*2-k,s+=mpx[i];
for(int i=2,s=mpy[1];i<=lm;i++)
sy[i]=sy[i-1]+s*2-k,s+=mpy[i];
pq.push({1,1,sx[1]+sy[1]});
while(1) {
qwq f=pq.top();pq.pop();
if(!mp[make_pair(f.x,f.y)]) {Ans=max(Ans,f.p);return;}
if(f.x!=n&&!vis[make_pair(f.x+1,f.y)]) vis[make_pair(f.x+1,f.y)]=1,pq.push({f.x+1,f.y,sx[f.x+1]+sy[f.y]});
if(f.y!=m&&!vis[make_pair(f.x,f.y+1)]) vis[make_pair(f.x+1,f.y)]=1,pq.push({f.x,f.y+1,sx[f.x]+sy[f.y+1]});
}
}
signed main() {
cin>>n>>m>>k;
for(int i=1;i<=k;i++)
aaa[i].x=rd(),aaa[i].y=rd();
for(int i=1;i<=k;i++)
a[i].x=aaa[i].x,a[i].y=aaa[i].y;
solve();
for(int i=1;i<=k;i++)
a[i].x=n-aaa[i].x+1,a[i].y=aaa[i].y;
solve();
for(int i=1;i<=k;i++)
a[i].x=aaa[i].x,a[i].y=m-aaa[i].y+1;
solve();
for(int i=1;i<=k;i++)
a[i].x=n-aaa[i].x+1,a[i].y=m-aaa[i].y+1;
solve();
cout<<Ans;
return 0;
}
本文来自博客园,作者:operator,转载请注明原文链接:https://www.cnblogs.com/operator-/p/17974781 ♪(^∀^●)ノシ