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\) 点为终点的最长距离,则显然有转移
其中 \(j\) 为所有能到达第 \(i\) 个点的点。
复杂度 \(O(n^2)\)。
100 pts
我们先考虑 \(a=0\) 且\(d=0\) 的情况。
这时能转移到一个点的点必定 \(x,y\) 轴都小于该点,所以我们可以使用二维偏序优化 dp,转移复杂度降至 \(O(\log n)\),总复杂度 \(O(n\log n)\)。
由于有角度的限制,我们可以将两条直线作为新的 \(x,y\) 轴。坐标变换公式如下:
其中 \((x,y)\) 为原坐标,\((x',y')\) 为转换后坐标。
转换后即可当作 \(a=0\) 且\(d=0\) 的情况解决。
坑点
-
当一个点前面没有任何可转移的点,且无法到达原点时,这个点转移时不能加一。
-
二维偏序排序时,\(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;
}
本文来自博客园,作者:Aurora_Borealis,转载请注明原文链接:https://www.cnblogs.com/Aurora-Borealis-Not-Found/p/17367603.html