求助,WA on 2,但是答案只差最后三位数,二分思路
查看原帖
求助,WA on 2,但是答案只差最后三位数,二分思路
389192
andychen_2012楼主2024/5/14 09:05

test 2 最后一个询问的答案是 918957089641524701,我的答案是 918957089641524619。

我的思路就是每个靶子的左右端点分开讨论,归类到负斜率和正斜率。假设有 poscposc 个正斜率,negcnegc 个负斜率。右上端点对应负斜率,右下端点对应正斜率,各自恰好有 nn 个点。左边的端点按 yy 值从小到大排序,下方的 posc−nposc-n 个归负斜率,上方的 neg−nneg-n 个归正斜率。

考虑到答案即为负斜率对应点的最大值减去正斜率对应点的最小值,因此对正负斜率分别二分即可。

check(t) 的规则是:对于正斜率,枚举每个 (x,y)(x,y),所有满足 s≤⌊y−tx⌋s \le \lfloor \frac{y-t}{x} \rfloor 的 ss 都能使得过 (x,y)(x,y) 的斜率为 ss 的直线经过 yy 轴上的点 y0y_0 满足 y0≥ty_0 \ge t;对于负斜率,枚举每个 (x,y)(x,y),所有满足 s≥⌊y−tx⌋s \ge \lfloor \frac{y-t}{x} \rfloor 的 ss 都能使得过 (x,y)(x,y) 的斜率为 ss 的直线经过 yy 轴上的点 y0y_0 满足 y0≤ty_0 \le t。

findpos(x) 是找到正斜率中最后一个满足 s≤xs \le x 的位置;findneg(x) 是找到负斜率中第一个满足 s≥xs \ge x 的位置。正负斜率都从小到大排序。

以下是代码

#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
inline ll read(){
	ll x=0;
	int f=0,ch=0;
	while(ch<48||ch>57) f=(ch=='-'),ch=getchar();
	while(ch>47&&ch<58) x=(x<<3)+(x<<1)+(ch&15),ch=getchar();
	return f?-x:x;
}
inline void write(ll x,char end='\n'){
	if(x==0){
		putchar('0');
		putchar(end);
		return;
	}
	if(x<0) putchar('-'),x=-x;
	int ch[40]={0},cnt=0;
	while(x){
		ch[cnt++]=(int)(x%10);
		x/=10;
	}
	while(cnt--) putchar(ch[cnt]+48);
	putchar(end);
}
const ll inf=4e18;
const int N=2e5+5;
int n,x1;
struct node{
	ll x,y;
}pos[N],neg[N],left[N];
inline bool cmp(node x,node y){
	return x.y<y.y;
}
int poscnt,negcnt,cnt;
int pcnt,ncnt;
ll posc[N],negc[N];
ll s[N];
inline ll getceil(ll x,ll y){return ceil(x*1.0/y);}
inline ll getfloor(ll x,ll y){return floor(x*1.0/y);}
inline int findneg(ll x){
	if(negc[ncnt]<x) return ncnt+1;
	int l=1,r=ncnt;
	while(l<r){
		int mid=(l+r)>>1;
		if(negc[mid]>=x) r=mid;
		else l=mid+1;
	}
	return l;
}
inline int findpos(ll x){
	if(posc[1]>x) return 0;
	int l=1,r=pcnt;
	while(l<r){
		int mid=(l+r+1)>>1;
		if(posc[mid]<=x) l=mid;
		else r=mid-1;
	}
	return l;
}
int sumneg[N<<1],sumpos[N<<1];
inline bool checkneg(ll t){
	for(int i=1;i<=ncnt+1;++i) sumneg[i]=0;
	for(int i=1;i<=ncnt;++i){
		ll x=neg[i].x,y=neg[i].y;
		ll g=getceil(y-t,x);
		int p=findneg(g);
		sumneg[p]++;
	}
	for(int i=1;i<=ncnt;++i){
		sumneg[i]+=sumneg[i-1];
		if(sumneg[i]<i) return 0;
	}
//	printf("successful: %lld\n",t);
	return 1;
}
inline bool checkpos(ll t){
	for(int i=1;i<=pcnt+1;++i) sumpos[i]=0;
	for(int i=1;i<=poscnt;++i){
		ll x=pos[i].x,y=pos[i].y;
		ll g=getfloor(y-t,x);
		int p=findpos(g);
		sumpos[p]++;
	}
	for(int i=pcnt;i>=1;--i){
		sumpos[i]+=sumpos[i+1];
		if(sumpos[i]<pcnt-i+1) return 0;
	}
//	printf("successful: %lld\n",t);
	return 1;
}
int main(){
//	freopen("P10190_2.in","r",stdin);
	int T=read();
	while(T--){
		n=read(),x1=read();
		poscnt=negcnt=0;
		cnt=0;
		for(int i=1;i<=n;++i){
			ll y1=read(),y2=read(),x2=read();
			pos[++poscnt]={x2,y1};
			neg[++negcnt]={x2,y2};
			left[++cnt]={x1,y1};
			left[++cnt]={x1,y2};
		}
		pcnt=0,ncnt=0;
		for(int i=1;i<=n*4;++i){
			s[i]=read();
			if(s[i]>0)
				posc[++pcnt]=s[i];
			if(s[i]<0)
				negc[++ncnt]=s[i];
		}
		if(pcnt<n){
			puts("-1");
			continue;
		}
		if(ncnt<n){
			puts("-1");
			continue;
		}
		sort(posc+1,posc+pcnt+1);
		sort(negc+1,negc+ncnt+1);
		sort(left+1,left+cnt+1,cmp);
		int gg=pcnt-poscnt;
		for(int i=1;i<=gg;++i) pos[++poscnt]=left[i];
		for(int i=gg+1;i<=cnt;++i) neg[++negcnt]=left[i];
		ll l=1,r=inf;
		while(l<r){
			ll mid=(l+r)>>1;
			if(checkneg(mid)) r=mid;
			else l=mid+1;
		}
		ll up=l;
		l=-inf,r=-1;
		while(l<r){
			ll mid=(l+r+1)>>1;
			if(checkpos(mid)) l=mid;
			else r=mid-1;
		}
		ll down=l;
		write(up-down);
	}
	return 0;
}
2024/5/14 09:05
加载中...