您的位置:首页 > 其它

JZOJ4877. 【NOIP2016提高A组集训第10场11.8】力场护盾

2016-11-08 22:36 337 查看

Description

ZMiG成功粉碎了707的基因突变计划,为了人类的安全,他决定向707的科学实验室发起进攻!707并没有想到有人敢攻击她的实验室,一时间不知所措,决定牺牲电力来换取自己实验室的平安。

在实验室周围瞬间产生了一个无限大的力场护盾,它看上去无懈可击!不过ZMiG拥有惊人的双向观察能力,经过他的反复观察,找到了这个护盾的N个弱点,他本想逐一击破,却发现一股神秘力量阻止了他的行为。原来他身处力场之中,受到了两股神秘力量的影响,这两股力量来自两个不同的方向并形成了一个小于180度的角,ZMiG每次可攻击的范围都受到这两个力的影响,当他攻击了点X之后,下一次可以攻击的点必须在以X为坐标原点的情况下,这两个力方向的夹角之间(包含边界)(具体意思可看样例)

ZMiG当然想打出一串最长的Combo,所以他想问问你最多可以攻击707弱点多少

Slution

我在做这道题时并不会怎样将那两个斜的向量给去掉,所以我打了个分段暴力,只能处理两条直线在同一象限的情况……

这道题我们考虑首先要将那恶心的倾斜的区间去掉。所以我们考虑新建一个以这两个力为轴的坐标系,再将每个点放进去。对于那两个力(x1,y1),(x2,y2),我们设它们分别为新坐标系中的x,y轴的单位向量。那么一个点(x,y)在新坐标系中的坐标(x’,y’)满足x′(x1,y1)+y′(x2,y2)=(x,y),我们用乘进去就会得到一条二元一次方程组,解出来就会得到(x’,y’),然后只要离散化一下,用树状数组求一个最长不下降子序列即可。

Code

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define db double
#define ll long long
using namespace std;
const int maxn=200005;
struct code{
db x,y;
}b[maxn];
ll n,i,t,j,k,l,num;
ll f[maxn];
double a2,b2,x,y,xx,yy,x2,y2;
bool cmp(code x,code y){
return x.x<y.x || x.x==y.x && x.y<y.y;
}
int lowbit(int x){
return x&(-x);
}
ll find(int x){
if (x<1) return 0;
return max(f[x],find(x-lowbit(x)));
}
void insert(int x){
if (x>num) return;
f[x]=max(f[x],t);
insert(x+lowbit(x));
}
db pan(db x,db y,db xx,db yy){
if (!(xx<0 && yy<0 && x<0 && y<0)) xx=abs(xx),yy=abs(yy),x=abs(x),y=abs(y);
return x*yy-y*xx;
}
int main(){
//  freopen("shield.in","r",stdin);freopen("shield.out","w",stdout);
freopen("data.in","r",stdin);
scanf("%lld%lf%lf%lf%lf",&n,&xx,&yy,&x2,&y2);
//if (pan(xx,yy,x2,y2)<0) swap(xx,x2),swap(yy,y2);
for (i=1;i<=n;i++){
scanf("%lf%lf",&x,&y);
b[i].x=(x*y2-x2*y)/(xx*y2-x2*yy);
b[i].y=(x*yy-xx*y)/(x2*yy-xx*y2);
swap(b[i].x,b[i].y);
}
sort(b+1,b+n+1,cmp);
for (i=1;i<=n;i++){
if (b[i].x!=x) num++;x=b[i].x;
b[i].x=num;
swap(b[i].x,b[i].y);
}
sort(b+1,b+n+1,cmp);
for (i=1;i<=n;i++){
t=find(b[i].y)+1;
insert(b[i].y);
}
t=find(num);
printf("%lld\n",t);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: