题解:P12148 【MX-X11-T2】「蓬莱人形 Round 1」所以我放弃了音乐
赛时脑抽,艰难过掉。
题目大意
给定平面直角坐标系中的 \(n\) 个点,每次选择一个点,依次检查 \((x+1,y+1),(x+1,y),(x+1,y-1)\) 并跳到这个点继续删除直到不能删为止,记为一次操作,求最小的操作次数。
70 pts
一个经典的网络流问题,直接暴力建图跑最大流即可。
100 pts
特殊性质 A 启发我们按照不同的 \(x\) 分开处理。故开 \(10^6\) 个 set 维护每个 \(x=i\) 时的所有 \(y\) 值。不难发现最终的答案是选择的不同路径的起点数量,我们要最小化这个东西。
接下来我们运用类似归纳法的思想得到贪心策略。
假设我们当前处理到了 \(x=i\) 的所有点,且这些点的贡献已经累计到答案中,那么 \(x=i\) 的这些点,无论是作为一条删除路径的起点或者是一条路径中的点,我们要为他们匹配一个 \(x=i+1\) 的后继,这样就能使 \(x=i+1\) 的点产生的贡献最小(因为能选择更少的起点)。
贪心策略:对于 \(x=i\) 的点 \(y\) 值从大到小处理,先匹配 \((x+1,y+1)\),再匹配 \((x+1,y)\),最后匹配 \((x+1,y-1)\)。
正确性:感性理解,如果不优先匹配 \(y\) 更大的那么对于后面的点就更不可能匹配到了,而 \(y\) 更小的还可以交给其他点处理,故不按照 \((x+1,y+1),(x+1,y),(x+1,y-1)\) 的顺序一定不优,满足贪心的最优子结构和贪心选择性的性质。
时间复杂度 \(\Theta(n \log n)\)。
代码
使用大量 stl,常数极大。
#include <bits/stdc++.h>
#define vint vector<int>
#define ll long long
#define pii pair<int,int>
#define all(x) x.begin(),x.end()
#define ull unsigned long long
#define uint unsigned int
#define rg register
#define il inline
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define sqr(x) ((x)*(x))
using namespace std;
const int INF=0x3f3f3f3f;
inline int read()
{
int w=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
w=(w<<1)+(w<<3)+(ch^48);
ch=getchar();
}
return w*f;
}
inline void write(int x)
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9) write(x/10);
putchar(x%10+'0');
}
const int N=1e6+10;
int n;
int x[N],y[N];
set<int,greater<int>> pos[N],tmp[N];
map<pii,int> to;
bool used[N];
int ans,maxx;
int maxs[N];
map<int,int> posx[N];
int main()
{
#ifndef ONLINE_JUDGE
//freopen("in.txt","r",stdin);
#endif
cin>>n;
rep(i,1,n) x[i]=read(),y[i]=read(),pos[x[i]].insert(y[i]),maxx=max(maxx,x[i]),to[make_pair(x[i],y[i])]=i;
ans=pos[1].size();
rep(i,1,maxx-1)
{
ans+=pos[i+1].size();
for(auto it=pos[i].begin();it!=pos[i].end();++it)
{
int x=i,y=*it;
if(to[make_pair(x+1,y+1)]&&!used[to[make_pair(x+1,y+1)]])
{
--ans,used[to[make_pair(x+1,y+1)]]=1;
continue;
}
if(to[make_pair(x+1,y)]&&!used[to[make_pair(x+1,y)]])
{
--ans,used[to[make_pair(x+1,y)]]=1;
continue;
}
if(to[make_pair(x+1,y-1)]&&!used[to[make_pair(x+1,y-1)]])
{
--ans,used[to[make_pair(x+1,y-1)]]=1;
continue;
}
}
}
cout<<ans<<endl;
return 0;
}

浙公网安备 33010602011771号