【JSOI2018】絕地反擊

題面

50pts

首先固然是二分答案\(mid\)
對於每個點,以它爲圓心的圓,交上攻擊軌道;
那麼這個點到攻擊軌跡的可達範圍就是一段圓弧。c++

怎麼求這段圓弧呢?網絡

咱們知道圓弧能夠用其兩端點對於圓心的弧度(角度)來表示。
已知三角形的三邊\(R1,R2,Dist\),利用餘弦定理,咱們能夠求出角\(θ\)
而後咱們也能夠輕易得知\(C\)對於圓心\(A\)的弧度\(α\)
那麼圓弧兩端點的弧度分別爲\(α±θ\)dom

假設一個圓弧覆蓋正多邊形的頂點,那麼稱圓弧和這個頂點能夠匹配。
如今就是問:有沒有一個攻擊軌道內接正多邊形偏轉角度,
使得圓弧和正多邊形的頂點存在完美匹配。spa

假設如今存在一種可行的方案,
若是這個正多邊形沒有一個頂點與某一個圓弧的一個端點重合的話,
那麼我能夠抖動這個正多邊形直到其的一個頂點與某一個圓弧的一個端點重合爲止,
這個我是想說,若是存在可行的方案,那麼必定存在一種可行的方案,使得該正多邊形有一個頂點與某個圓弧的一個端點重合。
因爲圓弧的端點的個數有\(O(n)\)
因此枚舉重合的那個端點,而後就能夠經過這個端點肯定正多邊形的其餘頂點。
而後就能夠建出二分圖,問是否有完美匹配了,完美匹配能夠用\(Hungary\)\(Maxflow\)\(O(n^3)\)解決。
複雜度是\(O(n^4 log n)\)的,能夠過50分。code

100pts

首先咱們注意到,
雖然每一個圓弧的端點對應一種偏轉角度
這些偏轉角度彷佛遍及\(360°\),但其實這些偏轉角度是能夠\(mod 2*π/n\)的,由於正多邊形的頂點互相等價。
因此說咱們實際的最大偏轉角度是不超過\(2*π/n\)blog

先把全部偏轉角度\(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\)有沒有新增的增廣路。it

一次退流/加邊操做就是\(O(m)\)的,在本題中\(m=n^2(n?)\)
因爲每一個點只有一次會退流/加邊,因此總共是\(O(n^3)\)
加上預處理的網絡流是\(O(n^3)\)的。ast

加上二分,總共是\(O(n^3 log n)\)class

代碼

#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;
}
相關文章
相關標籤/搜索