题面

50pts

首先当然是二分答案\(mid\),

对于每一个点,以它为圆心的圆,交上攻击轨道;

那么这个点到攻击轨迹的可达范围就是一段圆弧。

怎么求这段圆弧呢?

我们知道圆弧可以用其两端点对于圆心的弧度(角度)来表示。

已知三角形的三边\(R1,R2,Dist\),利用余弦定理,我们可以求出角\(θ\)。

然后我们也可以轻易得知\(C\)对于圆心\(A\)的弧度\(α\)。

那么圆弧两端点的弧度分别为\(α±θ\)。

假设一个圆弧覆盖正多边形的顶点,那么称圆弧和这个顶点可以匹配。

现在就是问:有没有一个攻击轨道内接正多边形偏转角度,

使得圆弧和正多边形的顶点存在完美匹配。

假设现在存在一种可行的方案,

如果这个正多边形没有一个顶点与某一个圆弧的一个端点重合的话,

那么我可以抖动这个正多边形直到其的一个顶点与某一个圆弧的一个端点重合为止,

这个我是想说,如果存在可行的方案,那么一定存在一种可行的方案,使得该正多边形有一个顶点与某个圆弧的一个端点重合。

由于圆弧的端点的个数有\(O(n)\),

所以枚举重合的那个端点,然后就可以通过这个端点确定正多边形的其他顶点。

然后就可以建出二分图,问是否有完美匹配了,完美匹配可以用\(Hungary\)或\(Maxflow\),\(O(n^3)\)解决。

复杂度是\(O(n^4 log n)\)的,可以过50分。

100pts

首先我们注意到,

虽然每个圆弧的端点对应一种偏转角度

这些偏转角度似乎遍布\(360°\),但其实这些偏转角度是可以\(mod 2*π/n\)的,因为正多边形的顶点互相等价。

所以说我们实际的最大偏转角度是不超过\(2*π/n\)。

先把所有偏转角度\(mod 2*π/n\)后,从小到大排序。

对于一个圆弧而言,由于最大的偏转角度不超过相邻两顶点间距

所以在偏转过程中,不能变得能匹配的顶点不超过\(1\)个,能变得不能匹配的顶点不超过\(1\)个。

也就是说,从\(0\)到最大偏转角度对应的残留网络的变化容量的边不超过\(2*n\)条。

所以我们利用网络流的退流,来只对残留网络进行局部修改。

具体而言:

1.删边

比如说一条\((u,v)\)的边容量变为\(0\),那么假如这条边有\(x\)的流量,那么肯定要把最大流减掉\(x\)。

然后要把这条边的双向容量归零。

从\(u\)到\(1\)找出总流量为\(x\)的增广路,把它们都流量翻转;这个可以直接用最大流来实现,限制住初始进入的流量不超过\(x\)即可;

同理,从\(T\)到\(v\)跑一遍最大流。

最后还要从\(1\)到\(T\)检查有没有别的增广路。

2.加边

这个直接加就好了,最后也要检查从\(1\)到\(T\)有没有新增的增广路。

一次退流/加边操作就是\(O(m)\)的,在本题中\(m=n^2(n?)\)

由于每个点只有一次会退流/加边,所以总共是\(O(n^3)\)。

加上预处理的网络流是\(O(n^3)\)的。

加上二分,总共是\(O(n^3 log n)\)。

代码

#include<bits/stdc++.h>
#define ll long long
#define db double
#define fo(i,x,y) for(int i=x;i<=y;i++)
#define fd(i,x,y) for(int i=x;i>=y;i--)
using namespace std; const int maxn=407,maxm=maxn*maxn;
const db pi=acos(-1); int n,m,Last=1;
db Step; struct P{
int x,y;
}a[maxn]; void Init(){
scanf("%d%d",&n,&m);
fd(i,n,1) scanf("%d%d",&a[i].x,&a[i].y);
//random_shuffle(a+1,a+n+1);
Step=2*pi/n;
} int N;
db q[maxn*2],L[maxn],R[maxn];
void newQuery(db x){
while (x>=-pi+Step) x-=Step;
while (x<-pi) x+=Step;
q[++N]=x;
}
int fi[maxn],ne[maxm],la[maxm],va[maxm],tot,T;
void add(int a,int b,int c){
tot++;
ne[tot]=fi[a];
la[tot]=b;
va[tot]=c;
fi[a]=tot;
}
void Add(int a,int b,int c){
add(a,b,c);
add(b,a,0);
}
int bz[maxn],id;
int sap(int v,int flow){
bz[v]=id;
if (v==T) return flow;
for(int k=fi[v];k;k=ne[k])
if (bz[la[k]]<id && va[k]){
int i=sap(la[k],va[k]&flow);
if (i){
va[k]-=i;
va[k^1]+=i;
return i;
}
}
return 0;
}
int go_flow(int St,int Next,int Lim=0x7fffffff){
int res=0;
T=Next;
while (1){
id++;
int temp=sap(St,1);
if (temp){
res+=temp;
if (res==Lim) break;
}else break;
}
return res;
}
int Road[maxn][maxn],res;
int cnt[maxn];
bool check(db ang){
fo(j,1,n){
if (cnt[j]>=2) continue;
db y=ang;
fo(i,1,n){
if (L[j]>R[j] && (L[j]<=y && y<=R[j]+pi*2 || L[j]-pi*2<=y && y<=R[j]) || L[j]<=R[j] && L[j]<=y && y<=R[j]){
if (!Road[j][i]){
Add(1+j,1+n+i,1);
Road[j][i]=tot;
//cnt[j]++;
/*int z=go_flow(1+n+i,n+n+2)&go_flow(1,1+j);
res+=z;
va[tot]^=z;
va[tot^1]^=z;*/
if (cnt[j]){
cnt[j]++;
break;
}
}
}else{
if (Road[j][i]){
int k=Road[j][i];
if (va[k]){
va[k]=va[k^1]=0;
go_flow(n+n+2,1+n+i,1);
go_flow(1+j,1,1);
res--;
}
va[k^1]=va[k]=0;
Road[j][i]=0;
cnt[j]++;
}
}
y+=Step;
}
}
res+=go_flow(1,n+n+2);
return res>=n;
}
bool judge(db rad){
tot=1;
res=0;
memset(fi,0,sizeof fi);
memset(cnt,0,sizeof cnt);
fo(i,1,n) Add(1,1+i,1);
fo(i,1,n) Add(1+n+i,n+n+2,1);
memset(Road,0,sizeof Road); N=0;
fo(i,1,n){
db Dist=sqrt(a[i].x*a[i].x+a[i].y*a[i].y);
if (rad+m<Dist || Dist<m-rad || a[i].x==0 && a[i].y==0 && rad<m) return false;
if (rad<m+Dist){
db Alpha=atan2(a[i].y,a[i].x),Beta=acos((m*m+Dist*Dist-rad*rad)/(2.0*m*Dist));
L[i]=Alpha-Beta;
R[i]=Alpha+Beta;
if (L[i]<-pi) L[i]+=2*pi;
if (R[i]>=pi) R[i]-=2*pi;
}else{
L[i]=-pi;
R[i]=pi;
}
newQuery(L[i]);
newQuery(R[i]);
}
sort(q+1,q+N+1);
if (n<=10){
fo(i,1,N) if ((i==Last || q[i]-q[i-1]>1e-7) && check(q[i])){
Last=i;
//printf("%d\n",i);
return true;
}
return false;
}
/*fd(i,N,1) if ((i==N || q[i+1]-q[i]>1e-7) && check(q[i])){
printf("%d\n",i);
return true;
}*/
fo(i,Last,N) if ((i==Last || q[i]-q[i-1]>1e-7) && check(q[i])){
Last=i;
//printf("%d\n",i);
return true;
}
fo(i,1,Last-1) if ((i==1 || q[i]-q[i-1]>1e-7) && check(q[i]+Step)){
//Last=i;
//printf("%d\n",i);
return true;
}
return false;
}
db Ans;
void Solve(){
db l=0,r=200;
while (r-l>1e-7){
db mid=(l+r)/2;
if (judge(mid)) r=mid;
else l=mid;
}
Ans=l;
} void Print(){
printf("%.8lf\n",Ans);
} int main(){
freopen("3.in","r",stdin);
freopen("3.out","w",stdout);
Init();
Solve();
Print();
return 0;
}

【JSOI2018】绝地反击的更多相关文章

  1. 【BZOJ5316】[JSOI2018]绝地反击(网络流,计算几何,二分)

    [BZOJ5316][JSOI2018]绝地反击(网络流,计算几何,二分) 题面 BZOJ 洛谷 题解 很明显需要二分一个答案. 那么每个点可以确定的范围就是以当前点为圆心,二分出来的答案为半径画一个 ...

  2. BZOJ5316 : [Jsoi2018]绝地反击

    若$R=0$,那么显然答案为离原点最远的点到原点的距离. 否则若所有点都在原点,那么显然答案为$R$. 否则考虑二分答案$mid$,检查$mid$是否可行. 那么每个点根据对应圆交,可以覆盖圆上的一部 ...

  3. LGP4518[JSOI2018]绝地反击

    题解: 只要确定了每艘飞船的就位位置,就可以用二分+网络流求得答案: 定义偏转角度$a$为离$x$正半轴逆时针最近的边的弧度,$a \in [0,\frac{2\pi}{n})$ 二分一个值,对于一个 ...

  4. 洛谷P4518 [JSOI2018]绝地反击(计算几何+二分图+退流)

    题面 传送门 题解 调了咱一个上午-- 首先考虑二分答案,那么每个点能够到达的范围是一个圆,这个圆与目标圆的交就是可行的区间,这个区间可以用极角来表示 首先,如果我们知道这个正\(n\)边形的转角,也 ...

  5. yyb省选前的一些计划

    突然意识到有一些题目的计划,才可以减少大量查水表或者找题目的时间. 所以我决定这样子处理. 按照这个链接慢慢做. 当然不可能只做省选题了. 需要适时候夹杂一些其他的题目. 比如\(agc/arc/cf ...

  6. LOJ 2548 「JSOI2018」绝地反击 ——二分图匹配+网络流手动退流

    题目:https://loj.ac/problem/2548 如果知道正多边形的顶点,就是二分答案.二分图匹配.于是写了个暴力枚举多边形顶点的,还很愚蠢地把第一个顶点枚举到 2*pi ,其实只要 \( ...

  7. 【LOJ】#2548. 「JSOI2018」绝地反击

    题解 卡常卡不动,我自闭了,特判交上去过了 事实上90pts= = 我们考虑二分长度,每个点能覆盖圆的是一段圆弧 然后问能不能匹配出一个正多边形来 考虑抖动多边形,多边形的一个端点一定和圆弧重合 如果 ...

  8. JSOI2018简要题解

    来自FallDream的博客,未经允许,请勿转载,谢谢. 有幸拜读到贵省的题目,题的质量还不错,而且相比zjoi可做多了,简单发一下题解吧. 还有就是,怎么markdown在博客园上的代码这么丑啊 「 ...

  9. JSOI2018 简要题解

    潜入行动 复杂度分析题. 定义状态fi,j,0/1,0/1f_{i,j,0/1,0/1}fi,j,0/1,0/1​表示以iii为根子树放jjj个机器iii这个放不放,iii这个是否已放来进行dpdpd ...

随机推荐

  1. js 过滤非法字符

    demo = 'zhang#@$san'; reg=/[`~!@#$%^&*()_+<>?:"{},.\/;'[\]]/im; if(reg.test(demo)){ t ...

  2. 牛客多校第五场 A digits 2 签到

    题意: 给定一个n,输出一个数,要求这个数所有位之和整除n,并且这个数也整除n,并且位数不许多于1e4 题解: 把这个数n输出n遍. #include<iostream> using na ...

  3. SPSS分类分析:决策树

    SPSS分类分析:决策树 一.决策树(分析-分类-决策树) "决策树"过程创建基于树的分类模型.它将个案分为若干组,或根据自变量(预测变量)的值预测因变量(目标变量)的值.此过程为 ...

  4. day25-静态、组合、继承

    #!/usr/bin/env python # -*- coding:utf-8 -*- # ----------------------------------------------------- ...

  5. 使用JDK自带功能,实现一个简单的Web Service接口发布

    万事开头难,本篇文章的目的就是使用JDK自带的功能,实现一个最简单的Web Service接口的发布. 下图是项目的组成,主要有三个部分,一个接口(WS),一个接口的实现类(WSImp),还有一个接口 ...

  6. 17.splash_case02

    # 抓取<我不是药神>的豆瓣评论 import csv import time import requests from lxml import etree fw = open('doub ...

  7. Java中循环体的初步了解以及另一种随机数的获取方法

    Math中的相关操作 随机数 Java中除了可以直接导入Random类,获取随机数,还可以通过本身自带的Math方法去获取随机数.Math.random()可以产生随机小数,区间范围为[0.0,1.0 ...

  8. ssm项目中使用拦截器加上不生效解决方案

    在很多时候,需要拦截器来帮助我们完成一些特定的工作,比如获取请求的参数,本身在request这种获取数据就是一次磁盘的io, 如果在filter中获取了参数,那么在controller中就不能获取相关 ...

  9. Linux网桥端口的arp问题

    Linux的brctl addif命令可以将一个接口加入到既有的网桥中,接下来,这个接口就成了brport,属于一个从属的接口,然而你还是可以看到它的,并且可以为它添加IP地址,然后route命令会显 ...

  10. PHP实现图片的汉明码提取与降维

    作者感言:数学不好,遇到算法问题分分钟狗带,毫无转寰的余地-_-||| 最近心血来潮,看了相似图片的搜索,最最最初级的方法即提取汉明码,之后匹配汉明距离.当然,在数以亿计的汉明码中,要筛出需要的图片, ...