Jzoj4877 力场护盾(红警系列)

ZMiG成功粉碎了707的基因突变计划,为了人类的安全,他决定向707的科学实验室发起进攻!707并没有想到有人敢攻击她的实验室,一时间不知所措,决定牺牲电力来换取自己实验室的平安。
    在实验室周围瞬间产生了一个无限大的力场护盾,它看上去无懈可击!不过ZMiG拥有惊人的双向观察能力,经过他的反复观察,找到了这个护盾的N个弱点,他本想逐一击破,却发现一股神秘力量阻止了他的行为。原来他身处力场之中,受到了两股神秘力量的影响,这两股力量来自两个不同的方向并形成了一个小于180度的角,ZMiG每次可攻击的范围都受到这两个力的影响,当他攻击了点X之后,下一次可以攻击的点必须在以X为坐标原点的情况下,这两个力方向的夹角之间(包含边界)(具体意思可看样例)

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

这道题需要一点点向量的知识,让后就可以实现坐标系之间的转换了

设两个向量为 (x1,y1) (x2,y2)

那么一个点 (x,y) 在新的坐标系的映射(x',y')里就满足以下方程

x'(x1,y1)+y'(x2,y2)=(x,y)

解方程即可得到x'和y'

但是坑点是精度问题,这道题要用数据结构来维护而且排序的时候也要考虑精度问题

比如,原本本地AC的code是这样的:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define D double
#define mid (l+r>>1)
using namespace std;
struct dt{ D a,b; } s[200010];
int n,m,r[200010],w[800080],f[200010]; 
D x1,y1,x2,y2,c1,c2,v[200010];
inline bool cmp(dt a,dt b){ return a.a<b.a; }
void update(int l,int r,int x,int p,int k){
	if(l==r){ w[x]=max(w[x],k); return; }
	if(p<=mid) update(l,mid,x<<1,p,k);
	  else update(mid+1,r,x<<1|1,p,k);
	w[x]=max(w[x<<1],w[x<<1|1]);
}
int query(int l,int r,int x,int L,int R){
	if(L<=l && r<=R) return w[x];
	int Ans=0;
	if(L<=mid) Ans=max(Ans,query(l,mid,x<<1,L,R));
	if(mid<R) Ans=max(Ans,query(mid+1,r,x<<1|1,L,R));
	return Ans;
}
int main(){
	freopen("shield.in","r",stdin);
	freopen("shield.out","w",stdout);
	scanf("%d",&n);
	scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
	for(int i=1;i<=n;++i){
		 scanf("%lf%lf",&c1,&c2);
		 s[i]=(dt){(c1*y2-c2*x2)/(x1*y2-y1*x2),(c1*y1-c2*x1)/(y1*x2-x1*y2)};
	}
	sort(s+1,s+1+n,cmp);
	for(int i=1;i<=n;++i) v[i]=s[i].b;
	sort(v+1,v+1+n); 
	for(int i=1;i<=n;++i) r[i]=lower_bound(v+1,v+1+n,s[i].b)-v;
	for(int i=1;i<=n;++i){ f[i]=query(0,n,1,0,r[i])+1; update(0,n,1,r[i],f[i]); } 
	printf("%d\n",w[1]);
}
但是被精度卡剩60pts

所以必须这样写:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#define D double
#define mid (l+r>>1)
using namespace std;
struct dt{ D a,b; int r; } s[200010];
int n,m,w[800080],f[200010]; 
D x1,Y1,x2,y2,c1,c2; 
inline bool cmp(dt a,dt b){ return fabs(a.a-b.a)<10e-7?a.r<b.r:a.a<b.a; }
inline bool cmp2(dt a,dt b){ return a.b<b.b; }
void update(int l,int r,int x,int p,int k){
	if(l==r){ w[x]=max(w[x],k); return; }
	if(p<=mid) update(l,mid,x<<1,p,k);
	  else update(mid+1,r,x<<1|1,p,k);
	w[x]=max(w[x<<1],w[x<<1|1]);
}
int query(int l,int r,int x,int L,int R){
	if(L<=l && r<=R) return w[x];
	int Ans=0;
	if(L<=mid) Ans=max(Ans,query(l,mid,x<<1,L,R));
	if(mid<R) Ans=max(Ans,query(mid+1,r,x<<1|1,L,R));
	return Ans;
}
int main(){
	freopen("shield.in","r",stdin);
	freopen("shield.out","w",stdout);
	scanf("%d",&n);
	scanf("%lf%lf%lf%lf",&x1,&Y1,&x2,&y2);
	for(int i=1;i<=n;++i){
		 scanf("%lf%lf",&c1,&c2);
		 s[i]=(dt){(D)(c1*y2-c2*x2)/(x1*y2-Y1*x2),(D)(c1*Y1-c2*x1)/(Y1*x2-x1*y2)};
	}
	sort(s+1,s+1+n,cmp2);
	for(int i=1;i<=n;++i) s[i].r=s[i].b-s[i-1].b<10e-7?s[i-1].r:s[i-1].r+1;
	sort(s+1,s+1+n,cmp);
	for(int i=1;i<=n;++i){ f[i]=query(0,n,1,0,s[i].r)+1; update(0,n,1,s[i].r,f[i]); } 
	printf("%d\n",w[1]);
}

posted @ 2017-10-31 16:29  扩展的灰(Extended_Ash)  阅读(541)  评论(0编辑  收藏  举报