[CF780H]Intranet of Buses
Posted Tan_tan_tann
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CF780H]Intranet of Buses相关的知识,希望对你有一定的参考价值。
Intranet of Buses
题解
计算几何出乎意料地好调,只调了一个小时,但卡精度二分
50
50
50 次还是太离谱了。
首先,原题相当于给了我们一个奇怪 n n n 边形,让我们取该多边形的周长上 m m m 个等分点,使得它们中与相邻两个点的连线的最大长度最小。
与相邻连线的最大长度最小,这使得我们很快想到了二分这个最大长度。但它的等分点的位置不是固定的,是在不断运动的的,我们将这些等分点连接后形成的新的 m m m 边形的形状与边长都是会变的,不好直接判断。
我们先单独看一下某两个相邻的等分点点它们的连线边长变化,由于这个运动是不断循环的,我们可以只考虑 0 , C m ) 0,\\frac{C}{m}) 0,mC) 的时间区间内的边长变化。
在这段时间中,这些点有可能经过不同的边,方向发生变化,也有可能一直在一条边上运动。我们可以考虑将它们的运动拆分成在不同的边对上的运动,而当它们运动的边与它们的起点终点是固定的时候,它们运动时其间之间的距离明显是一个二次函数。
我们设点 u u u, v v v 的起点分别为 ( a x , a y ) , ( b x , b y ) (ax,ay),(bx,by) (ax,ay),(bx,by),运动的方向向量分别为 ( cos α , sin α ) , ( cos β , sin β ) (\\cos\\,\\alpha,\\sin\\,\\alpha),(\\cos\\,\\beta,\\sin\\,\\beta) (cosα,sinα),(cosβ,sinβ),它们运动的距离 x x x 与它们间的距离可以表示为:
y = ( a x + x cos α − b x − x cos β ) 2 + ( a y + x sin α − b y − x sin β ) 2 = ( ( cos α − cos β ) 2 + ( sin α − sin β ) 2 ) x 2 + 2 ( cos α − cos β + sin α − sin β ) x + ( a x − b x ) 2 + ( a y − b y ) 2 \\begin{array}{cc} y=(ax+x\\cos\\,\\alpha-bx-x\\cos\\,\\beta)^2+(ay+x\\sin\\,\\alpha-by-x\\sin\\,\\beta)^2 \\\\ =((\\cos\\,\\alpha-\\cos\\,\\beta)^2+(\\sin\\,\\alpha-\\sin\\,\\beta)^2)x^2+2(\\cos\\,\\alpha-\\cos\\,\\beta+\\sin\\,\\alpha-\\sin\\,\\beta)x+(ax-bx)^2+(ay-by)^2\\end{array} y=(ax+xcosα−bx−xcosβ)2+(ay+xsinα−by−xsinβ)2=((cosα−cosβ)2+(sinα−sinβ)2)x2+2(cosα−cosβ+sinα−sinβ)x+(ax−bx)2+(ay−by)2
而我们是想要它的长度小于我们二分的值,而它又明显是一个下凹的函数,我们可以通过求根公式将它的合法区间解出来,这对应的是多边形上一段边的区间,可以被转化为一段时间区间。
对于一个等分点,它在多边形上对应的区间是固定的,我们可以找到对于它来说合法的边的区间,转化为时间区间。由于它对应的边对有多个,所以它的合法时间区间也会有多个,我们需要将它求区间并,得到它的合法时间集合。
而我们需要使得有一个时刻,相邻的所有等分点之间距离都要小于我们二分的 m i d mid mid,相当于我们要找到对于所有合法时间集合的交集。如果存在交集,当前的距离就是合法的。
如何同时维护区间交集与并集呢? ODT!!!,不会真的有人想打吧。。。
很明显,肯定有一个合法的时间点是端点,我们相当于要找到一个被所有几何包含的端点,于是我们可以采用差分的思想。
我们可以将加入的所有合法时间区间的左右端点拿出来排序,并记录下它们的颜色(即它们属于哪一个等分点的合法时间集合)。加入左端点时对当前区间对应颜色的 c n t + + cnt++ cnt++,加入右端点时对 c n t − − cnt-- cnt−−。当某时刻某种颜色的 c n t cnt cnt 大于 0 0 0 时,说明它在此时合法。
我们的任务变成了排序后看有没有某一个时刻所有颜色的 c n t cnt cnt 都大于 0 0 0 ,所有等分点都合法,这就很好维护了。因为要排序,所以单次判断是 O ( n log n ) O\\left(n\\log\\,n\\right) O(nlogn) 的。
我们只需要预处理出来每个等分点对应的分段函数,再二分满足条件的最大边长即可。
时间复杂度 O ( n log 2 n ) O\\left(n\\log^2\\,n\\right) O(nlog2n) ,但这题精度卡得离谱,要二分 50 50 50 次。
源码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 200005
#define MAXM 400005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
typedef long long LL;
typedef unsigned long long uLL;
const LL INF=0x7f7f7f7f7f7f7f7f;
const int mo=998244353;
const int jzm=2333;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-9;
typedef pair<double,double> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
int add(int x,int y){return x+y<mo?x+y:x+y-mo;}
int qkpow(int a,int s){int t=1;while(s){if(s&1)t=1ll*a*t%mo;a=1ll*a*a%mo;s>>=1;}return t;}
double sqr(double x){return x*x;}
int n,m,tot,cnt[MAXN],idx;double summ,alen;
struct point{
double x,y;point(){x=y=0;}
point(double X,double Y){x=X;y=Y;}
point operator + (const point &rhs)const{return point(x+rhs.x,y+rhs.y);}
}a[MAXN];
double dist(point x,point y){return sqrt(sqr(x.x-y.x)+sqr(x.y-y.y));}
point walk(point p,double len,point agl){return p+point(agl.x*len,agl.y*len);}
struct line{
point s,t,agl;double len,pre;line(){len=pre=0;}
line(point S,point T){s=S;t=T;len=dist(s,t);agl=point((t.x-s.x)/len,(t.y-s.y)/len);}
}s[MAXN];
struct ming{
double l,r,a,b,c;ming(){l=r=a=b=0;}
ming(double L,double R,double A,double B,double C){l=L;r=R;a=A;b=B;c=C;}
double delta(){return sqr(b)-4.0*a*c;}
double leftRoot(){return (-b-sqrt(delta()))/(2.0*a);}
double rightRoot(){return (-b+sqrt(delta()))/(2.0*a);}
}b[MAXM];
struct range{
double wh;int col;bool typ;range(){wh=0;col=0;typ=0;}
range(double X,int Y,bool Z){wh=X;col=Y;typ=Z;}
bool friend operator < (const range &x,const range &y){if(Fabs(x.wh-y.wh)<eps)return x.typ>y.typ;return x.wh<y.wh;}
}d[MAXM<<2];
void insert(double L,double R){
if(L>R)return ;
int l=(int)floor(L/alen),r=(int)floor(R/alen);
if(l>m)l-=m,L-=summ;if(r>m)r-=m,R-=summ;int las=idx;
if(l==r){
d[++idx]=range(L-alen*l,l,1);
d[++idx]=range(R-alen*l,l,0);
}
else{
d[++idx]=CF游戏出现out of memory 怎么解决