Challenge of Wisdom
Problem Description
“I have a great deal of lands. They’re divided into N*M grids (N, M <= 1,000,000,000). When you are in (x, y), you may move into (x+1, y) or (x, y+1). I have P (P <= 100,000) treasures in the lands; each time, you can pick up anything you like.”
“Now, I’ll give you a map of my treasures; tell me, wise boy, how many times you need to pick up all the treasures?”
Input
This problem contains multiple test cases.
Each test case begins with 3 integers N, M and P. then followed by P lines, each lines contains 2 numbers: x, y, representing the location of a treasure.
Output
For each test case, output the minimum times I need.
Sample Input
7 7 7
1 2
1 4
2 4
2 6
4 4
4 7
6 6
Sample Output
2
题意
在一个n*m大小的坐标轴上,有p个点,坐标为 ( x i , y i ) (x_i,y_i) (xi,yi)初始在(0,0)处,每次可以选择从(x,y)移动至(x+1,y)或(x,y+1)。从最少需要多少次从(0,0)出发,才能经历所有点。
题解:
将p个点按x主键,y为副键升序排列。这样就可以忽略x轴,只考虑y轴。将p个点的y坐标提取出来形成序列a。
那么问题就变为一个序列,最少能将其拆分为多少个非降子序列。会发现这和导弹拦截问题很像。所以求序列a的最长下降子序列即可(Dilworth定理了解一下)。
#include<stdio.h>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<set>
#include<vector>
#include<queue>
#include<iterator>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define eps 1e-7
using namespace std;
typedef long long LL;
typedef pair<int, int> P;
const int maxn = 100100;
const int mod = 998244353;
struct node{
int x, y;
}p[maxn];
int a[maxn], dp[maxn], b[maxn];
bool cmp(node a, node b);
int main()
{
int n, m, q, i, j, k, l, ans;
while(scanf("%d %d %d", &n, &m, &q)!=EOF)
{
ans = 0;
for(i=0;i<q;i++)
scanf("%d %d", &p[i].x, &p[i].y);
sort(p, p+q, cmp);
for(i=0;i<q;i++)
a[i] = p[i].y;
l = q;
for(i=0;i<q;i++){
int pos = upper_bound(b+l, b+q, a[i])-b;
if(pos == l)b[--l] = a[i];
else b[pos-1] = a[i];
dp[i] = q-(pos-1);
ans = max(ans, dp[i]);
}
printf("%d\n", ans);
}
return 0;
}
bool cmp(node a, node b)
{
if(a.x != b.x)return a.x < b.x;
else return a.y < b.y;
}