asm_second 题解(坐标转换+二维偏序)

Question

洛谷提交端口

Asm.Def 在第一象限内找到了 \(n\) 个可疑点。他需要为导弹规划路径。

如图所示,导弹一开始在 \((0,0)\)。它只能朝着一定的方向——即严格夹在图中两条射线间的方向(白色部分)前进。注意,它不能沿着这两条射线前进,当然也不能停在原地。

当导弹到达某个可疑点后,它仍然只能朝着该范围内的方向前进,如上图。

求导弹最多能经过多少个可疑点。

输入格式

\(1\) 行包括 \(1\) 个整数 \(n\)
\(2\)\(4\)个整数 \(a,b,c,d\):代表两条射线的斜率分别是 \(\dfrac{a}{b}\)\(\dfrac{c}{d}\)
接下来 \(n\) 行,每行 \(2\) 个整数 \(x_i,y_i\),代表 \(i\) 号可疑点的坐标。

输出格式

一个整数,即最多能经过几个可疑点。

样例解释

数据范围

对于 30% 的数据,\(n \leq 1000,a=0,b=1,c=1,d=0\)

对于 60% 的数据,\(n \leq 1000\)

对于 100% 的数据有:

  • \(n \leq 10^5\)

  • \(0 \leq a,b,c,d \leq 10^5\)

  • \(\dfrac{a}{b}<\dfrac{c}{d}\)(即 \(\dfrac{a}{b}\) 为靠下的那条曲线)

  • \(\dfrac{a}{b} \neq \dfrac{0}{0},\dfrac{c}{d} \neq \dfrac{0}{0}\)

  • \(1 \leq x_i,y_i \leq 10^5\)

solution

60 pts

\(f_i\)\(i\) 点为终点的最长距离,则显然有转移

\[f_i=\max(f_j)+1 \]

其中 \(j\) 为所有能到达第 \(i\) 个点的点。

复杂度 \(O(n^2)\)

100 pts

我们先考虑 \(a=0\)\(d=0\) 的情况。

这时能转移到一个点的点必定 \(x,y\) 轴都小于该点,所以我们可以使用二维偏序优化 dp,转移复杂度降至 \(O(\log n)\),总复杂度 \(O(n\log n)\)

由于有角度的限制,我们可以将两条直线作为新的 \(x,y\) 轴。坐标变换公式如下:

\[x'=cx-dy \]

\[y'=by-ax \]

其中 \((x,y)\) 为原坐标,\((x',y')\) 为转换后坐标。

转换后即可当作 \(a=0\)\(d=0\) 的情况解决。

坑点

  1. 当一个点前面没有任何可转移的点,且无法到达原点时,这个点转移时不能加一。

  2. 二维偏序排序时,\(x\) 坐标相同时,\(y\) 坐标应降序排列。这样当 \(d=0\) 时,\(x\) 坐标相同的不会被计算。

code

asm_second.cpp

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define debug cout<<"debug\n"
#define vi vector<int>
#define imp map<int,int>
#define il inline
#define pb push_back
#define int ll
using namespace std;
const int N=2e5+5;
int n,tot,A,B,C,D,b[N<<1],f[N<<1],ta[N<<1];
struct node{
	int x,y,id;
	bool vis;
}a[N<<1];
bool cmp(node A,node B){
	if(A.x==B.x) return A.y>B.y;
	return A.x<B.x;
}
int lowbit(int x){
	return x&-x;
}
void add(int x,int d){
	while(x<=tot){
		ta[x]=max(ta[x],d);
		x+=lowbit(x);
	}
}
int query(int x){
	int sum=0;
	while(x>0){
		sum=max(sum,ta[x]);
		x-=lowbit(x);
	}
	return sum;
}
signed main(){
	freopen("asm_second.in","r",stdin);
	freopen("asm_second.out","w",stdout);
	cin>>n>>A>>B>>C>>D;
	bool ok=1;
	for(int i=1;i<=n;i++){
		int x,y;
		cin>>x>>y;
		a[i].id=i;
		if(y*D<x*C&&y*B>x*A){
			a[i].vis=0;
			ok=0;
		}else{
			a[i].vis=1;
		}
		a[i].x=C*x-D*y;
		a[i].y=B*y-A*x;
		b[i]=a[i].y;
	}
	if(ok){
		debug;
		cout<<"0\n";
		return 0;
	}
	sort(b+1,b+n+1);
	tot=unique(b+1,b+n+1)-b-1;
	for(int i=1;i<=n;i++){
		a[i].y=lower_bound(b+1,b+tot+1,a[i].y)-b;
	}
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;i++){
		if(a[i].vis&&query(a[i].y-1)==0){
			f[a[i].id]=0;
		}else{
			f[a[i].id]=max(f[a[i].id],query(a[i].y-1)+1);
		}
		add(a[i].y,f[a[i].id]);
	}
	int ans=0;
	for(int i=1;i<=n;i++){
		ans=max(ans,f[i]);
	}
	cout<<ans<<"\n";
	return 0;
}

附上对排程序(对拍代码为 std)

datamaker1.cpp

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define debug cout<<"debug\n"
#define vi vector<int>
#define imp map<int,int>
#define il inline
#define pb push_back
using namespace std;
//mt19937 seed(chrono::system_clock().now().time_sinci_epoch().count);

int main(){
	freopen("datamaker1.in","w",stdout); 
	srand(time(0));
	int n=20;
	cout<<n<<"\n";
	int A=1,B=rand()%6+1;
	int C=rand()%6+1,D=1;
	cout<<"1 3 2 0\n"; 
	for(int i=1;i<=n;i++){
		int x=rand()%100+1;
		int y=rand()%100+1;
		cout<<x<<" "<<y<<"\n";
	}
	return 0;
}

bl.cpp

点击查看代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const int SIZEN=100010;
class BIT{
public:
	int n;
	int s[SIZEN];
	#define lowbit(x) ((x)&(-x))
	void clear(int _n){
		n=_n;
		memset(s,0,sizeof(s));
	}
	void modify(int x,int t){
		for(;x<=n;x+=lowbit(x)) s[x]=max(s[x],t);
	}
	int pref_max(int x){
		int ans=0;
		for(;x;x-=lowbit(x)) ans=max(ans,s[x]);
		return ans;
	}
};
class Point{
public:
	LL x,y;
	int id;
};
void print(const Point &p){
	cout<<"("<<p.x<<","<<p.y<<" "<<p.id<<")";
}
bool operator < (const Point &a,const Point &b){
	if(a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}
LL operator * (const Point &a,const Point &b){
	return a.x*b.x+a.y*b.y;
}
int N;
Point P[SIZEN];
Point alpha1,alpha2;
LL Y[SIZEN]={0};int tot=0;
void coor_trans(void){//????浠?
	for(int i=0;i<=N;i++){
		LL a=P[i].x*alpha2.y-alpha2.x*P[i].y;
		LL b=alpha1.x*P[i].y-P[i].x*alpha1.y;
		a*=-1,b*=-1;//??懈????,??x,y????小??????
		P[i].x=a,P[i].y=b;
		Y[tot++]=b;
	}
	sort(Y,Y+tot);
	tot=unique(Y,Y+tot)-Y;
	for(int i=0;i<=N;i++) P[i].y=lower_bound(Y,Y+tot,P[i].y)-Y+1;
}
int dp[SIZEN]={0};
BIT T;
void work(void){
	sort(P,P+1+N);
	T.clear(N+1);
	for(int i=0,j=0;i<=N;i++){
		while(P[j].x<P[i].x){
			T.modify(P[j].y,dp[P[j].id]);
			j++;
		}
		dp[P[i].id]=T.pref_max(P[i].y-1)+1;
	}
	printf("%d\n",dp[0]-1);
}
void read(void){
	P[0].x=P[0].y=0;P[0].id=0;
	scanf("%d",&N);
	scanf("%I64d %I64d",&alpha1.y,&alpha1.x);
	scanf("%I64d %I64d",&alpha2.y,&alpha2.x);
	for(int i=1;i<=N;i++){
		scanf("%I64d%I64d",&P[i].x,&P[i].y);
		P[i].id=i;
	}
}
int main(){
	freopen("datamaker1.in","r",stdin);
	freopen("bl.out","w",stdout);
	read();
	coor_trans();
	work();
	return 0;
}

autocompare

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define debug cout<<"debug\n"
#define vi vector<int>
#define imp map<int,int>
#define il inline
#define pb push_back
using namespace std;
const int N=1e6; 
int main(){
	
	for(int i=1;i<=N;i++){
		system("datamaker1");
		system("asm_second");
		system("bl");
		debug;
		if(system("fc asm_second.out bl.out")){
			cout<<"WA\n";
			return 0;
		}else{
			cout<<"AC\n";
		}
	}  
	return 0;
}

posted @ 2023-05-02 13:39  Aurora_Borealis  阅读(22)  评论(0编辑  收藏  举报