您的位置:首页 > 其它

Gym 101246.H - “North-East” (二维LIS变形)

2017-10-16 20:34 441 查看
题意:给出n个点的坐标,现在有一个乐队,他可以从任一点出发,但是只能往右上方走(包括右方和上方),要经过尽量多的点。输出它可能经过的点和一定会经过的点。

思路:

  如果按x轴从小到大,y轴从大到小排序,是不是等价于求y这一维度上的LIS。然后我们很快能处理出LIS,我们同时还需要记录一下,y[i]位于LIS中的长度len[i]。然后我们拿一个dpInv数组记录一下,dpInv[i]:长度为i的时候,当前最大长度是多少。只要y[i] < dpInv[len[i] + 1],是不是这个点就可以落在LIS上了,所有满足这个条件的点,就是maybe点。然后maybe点中,所有cnt[len[i]] == 1的点,是不是就一定要出现了,因为它意味着长度为len[i]的LIS的点的数量只有1个。就是must点。

  

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
const int INF = 0x3f3f3f3f;
int dp[maxn], dpInv[maxn], len[maxn], cnt[maxn];
struct node{int x, y, id;}nodes[maxn];
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int n;
scanf("%d", &n);

for(int i = 1; i <= n; i++)
{
int x, y;
scanf("%d%d", &x, &y);
nodes[i] = {x, y, i};
}

sort(nodes + 1, nodes + 1 + n, [](node a, node b)
{
if(a.x != b.x) return a.x < b.x;
return a.y > b.y;
});

memset(dp, INF, sizeof(dp));
for(int i = 1; i <= n; i++)
{
int pos = lower_bound(dp + 1, dp + 1 + n, nodes[i].y) - dp;
dp[pos] = nodes[i].y;
len[i] = pos;
}
memset(dpInv, -INF, sizeof(dpInv));
int totLen = lower_bound(dp + 1, dp + 1 +  n, INF) - dp - 1;

vector<int>vec;
for(int i = n; i >= 1; i--)
{
int curLen = len[i];
if(curLen == totLen)
{
dpInv[curLen] = max(dpInv[curLen], nodes[i].y);
cnt[curLen]++;
vec.push_back(i);
}
else if(dpInv[curLen + 1] > nodes[i].y)
{
dpInv[curLen] = max(dpInv[curLen], nodes[i].y);
cnt[curLen]++;
vec.push_back(i);
}
}
vector<int>maybe, must;
for(auto o : vec)
{
maybe.push_back(nodes[o].id);
if(cnt[len[o]] == 1) must.push_back(nodes[o].id);
}

sort(maybe.begin(), maybe.end());
printf("%d", maybe.size());
for(auto o : maybe) printf(" %d", o); puts("");

sort(must.begin(), must.end());
printf("%d", must.size());
for(auto o : must) printf(" %d", o); puts("");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: