首页 > 其他分享 >CF1167G题解

CF1167G题解

时间:2023-02-12 19:12:42浏览次数:76  
标签:ld le set int 题解 正方形 ch CF1167G

CF1167G题解

传送门

简化题意:数轴上有 n 个不相交且处于坐标为非负整数的单位正方形,给 m 个询问点,求出把这个点右侧的数轴逆时针旋转至与左侧相交时的角度。

首先,碰撞时只能有以下两种情况:

1.正方形与数轴碰撞。

2.正方形与正方形碰撞。

对于第一种情况,我们通过画图就可以很好理解求法:

情况1

答案就是 \(\arctan \dfrac{1}{d}\) 。

对于第二中情况,我们可以证明,两个正方形只会在顶点上相交。

情况二

采用反证法,如果两个正方形的交点 A 在其中一个的边上(显然不可能都在边上),那么过 A 向其所在的边所对的正方形的底边作垂线,并连接 A 与旋转中心 M ,我们就可以通过角平分线的性质证明出 \(\triangle AMH\) 全等于 \(\triangle AMB\) ,因此 \(BM=HM\) ,而 B,M 都是整点,因此 \(BM\) 长为整数,所以 \(HM\) 长为整数,H 在整点上,这也就证明了交点一定在正方形顶点上。

那满足什么条件时才会在顶点上相交呢?

结合下图和上图我们可以推出,当 \(\left|d1-d2\right|\leqslant1\) 时两个正方形会相交在顶点上,这时答案为 \(2\times\arctan \dfrac{1}{\max(d1,d2)}\) 。

数学的部分结束了,我们就开始考虑做法。

对于情况一,我们可以通过双指针 \(O(n)\) 求出所有答案。但对于情况二,我们考虑到情况一的答案最小为 \(\arctan \dfrac{1}{3500}\) ,这时情况二里 \(\max(d1,d2)\) 为 \(7000\) ,也就是说要向两侧找最多 \(7000\) 个点,直接暴力找是 \(O(md)\) 的,过不了,但我们可以用 bitset 来维护每个询问点左右两侧 d 个点上是否有正方形,这样就可以把复杂度降到 \(O(\dfrac{nd}{w}+q)\) ,这样就可以通过此题。

#include<bits/stdc++.h>
#define ll long long
#define ld long double
using namespace std;
inline int read(){
	int s=0;
	char ch=getchar();
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
	return s;
}
const int N=200501;
const ld pi=acos(-1);//求π
int n,d,m,le,ri;
ll a[N],q[N];
bitset<7005>l,r,tmp;
ld work(int i,int j){
	return atan((ld)i/(ld)j);
}
int main(){
//	freopen("travel.in","r",stdin);
//	freopen("travel.out","w",stdout);
	n=read(),d=read();
	for(int i=1;i<=n;i++)a[i]=read();
	m=read();
	for(int i=1;i<=m;i++)q[i]=read();
	for(int i=1;i<=n&&a[i]<=q[1]+7000;i++){//处理第一个询问点前的情况
		if(a[i]>=q[1])r.set(a[i]-q[1]);
		else{
			le=i+1;
			if(a[i]>=q[1]-7001)l.set(q[1]-a[i]-1);
		}
	}
	for(int i=1;i<=m;i++){
		ld ans=0;
		int pos=0;
		if(l.test(0)||r.test(0))ans=pi/(ld)2.0;
		else ans=work(1,min(l._Find_first(),r._Find_first()));
		tmp=l&r;if(tmp.any())pos=tmp._Find_first(),ans=max(ans,pos?2*work(1,pos):pi);//d1=d2的情况
		tmp=(l<<1)&r;if(tmp.any())pos=tmp._Find_first(),ans=max(ans,2*work(1,pos));
		tmp=l&(r<<1);if(tmp.any())pos=tmp._Find_first(),ans=max(ans,2*work(1,pos));//|d1-d2|=1的情况
		printf("%.15Lf\n",ans);
		if(i==m)return 0;
		l<<=(q[i+1]-q[i]),r>>=(q[i+1]-q[i]);
		while(a[le]<q[i+1]){
			if(a[le]>=q[i+1]-7001)l.set(q[i+1]-a[le]-1);
			le++;
		}
		while(a[ri]<=q[i+1]+7000&&ri<=n){
			if(a[ri]>=q[i+1])r.set(a[ri]-q[i+1]);
			ri++;
		}
	}
}

标签:ld,le,set,int,题解,正方形,ch,CF1167G
From: https://www.cnblogs.com/Xttttr/p/17114470.html

相关文章

  • CF1784C Monsters (hard version) 题解
    为了便于表述,下文中用"数"替代怪物的血量。我们换一种不同于easyversion中的计算答案的方法。我们先还是按照easyversion中的贪心操作来消除,当一个数能通过这种贪......
  • CF1786E题解
    容易为本题的弱化版CF1786C想出一个贪心:#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongintn,a[1000000];signedmain(){ intT; scanf("%d",&......
  • ABC268 题解
    比赛链接:https://atcoder.jp/contests/abc268/tasks题解:C对于每个盘子统计一下转那几次(3种情况)能够满足条件//bySkyRainWind#include<bits/stdc++.h>#definempr......
  • YACS 2023年1月月赛 甲组 T2 分割数列(二) 题解
    题目链接继上个月的分割数列(一)又出了这道题。首先还是考虑$n^2DP$,设$f[i]$为分到$i$个的最小权重之和。转移枚举上一个在哪里分就行了。显然时间会超限,我们考虑......
  • YACS 2023年1月月赛 甲组 T1 树的独立集 题解
    题目链接半夜12:00我不睡觉来这里更文章来了。。。这次的甲组好简单,第一次$AK$了,这题看上去很难,要求什么不挨边,其实分析一下就是树形$DP$。首先要求不挨边,所以我......
  • 题解 LGP9018【[USACO23JAN] Moo Route G】
    problem现在有一条数轴,\(t\)表示当前时刻。在\(t=0\)时Bessie恰好处在\(x=0\)的位置。接下来,每秒钟Bessie会向左或者向右移动一个单位距离,我们保证Bessie是在......
  • flannel 低版本glog flag redefined error 问题解决
    最近在构建一个老版本的flannel的时候碰到了此问题,记录下,方便使用解决方法glideinstall--strip-vendor--strip-vcs参考资料https://stackoverflo......
  • go: cannot find main module, but found glide.lock 问题解决
    解决方法exportGO111MODULE=auto说明此问题主要是老golang项目构建可能会出现的,新的一般不对有此问题(都基于gomod了)参考资料https://github.co......
  • abc289g题解
    考虑枚举卖出的物品个数\(i\),把\(b_i\)从大到小排序。题目的某人会买物品的条件转化为\(b_i\geqp_j-c_j\),这说明卖出的物品的集合是排序后\(b\)的一段前缀,且卖出\(i\)个......
  • CF793G Oleg and chess 题解
    \(\text{类似于主席树优化建图,直接放一张图片。}\)#include<iostream>#include<cstdio>#include<string>#include<cstring>#include<vector>#include<map>#include......