传送门:点击打开链接
题意:一个赛车捡金币的游戏,刚开始的起点在x轴,赛车跑道宽为w,最左边是y轴。刚开始你可以选择在x轴的任意位置启动。有很多金币在赛道中,位置已经告诉你。还告诉了你一个r,当y轴方向的车速为v时,x轴的车速只能在[-v/r,v/r]这个区间中,说白了就是在y轴上移动s距离,x轴上只能移动[-w/r,w/r]距离。赛车在y轴方向只能朝正方向移动。问到达终点时,最多能拾到多少金币。
思路:把题目转换一下就能发现,当赛车在某个位置时,它接下来能拾到的金币的位置是跑道的位置和两条射线夹的面积的相交部分。假如我们让这两条射线分别与赛道两旁的边界相交,那么就能得到两个数字,分别记为a,b
最后我们能发现,本身是一个DAG模型,但是由于都很庞大,但是转换成(a,b) 以后,如果想捡了这个金币后还能捡到下一个金币,那么就要保证下一个金币的A比a大且B比b大,也可以相等。那么这就变成了一个二维无序LIS了,有一种很简单的方法就是,把a从小到大排序,那么之后对b做最长不下降子序列,那么就是答案了。因为此时能保证a绝对不会下降。
#include<map> #include<set> #include<cmath> #include<ctime> #include<stack> #include<queue> #include<cstdio> #include<cctype> #include<string> #include<vector> #include<cstring> #include<iomanip> #include<iostream> #include<algorithm> #include<functional> #define fuck(x) cout<<"["<<x<<"]" #define FIN freopen("input.txt","r",stdin) #define FOUT freopen("output.txt","w+",stdout) using namespace std; typedef long long LL; typedef pair<int, int>PII; const int MX = 1e5 + 5; const int mod = 1e9 + 7; const LL INF = 0x3f3f3f3f3f3f3f3f; struct Data { LL a, b; bool operator<(const Data &P)const { return a < P.a; } void read(int r, int w) { int x, y; scanf("%d%d", &x, &y); a = (LL)x * r + y; b = (LL)(w - x) * r + y; } } A[MX]; LL d[MX]; int main() { int n, r, w, h; //FIN; while(~scanf("%d%d%d%d", &n, &r, &w, &h)) { memset(d, INF, sizeof(d)); for(int i = 1; i <= n; i++) { A[i].read(r, w); } sort(A + 1, A + 1 + n); int ans = 0; for(int i = 1; i <= n; i++) { int id = upper_bound(d + 1, d + 1 + n, A[i].b) - d; ans = max(ans, id); d[id] = A[i].b; } printf("%d\n", ans); } return 0; }