GYM 101174 A

。。。

不是啊。
我acos一个1+2e-16它返回nan,这怎么调啊???
自己完美地solo完了整道题,结果没过,太可惜了(((
复杂度O(n)
考虑从头开始选,每选一条线段都会有对应的范围吧。这里范围的定义是『前n条线段组成的终点到原点的距离』
然后我们看一下终点是不是在区间里,
假设能到达,
我们定义ans[i]是前i条线段组成的终点到原点的距离
我们从终点倒着求,现在我们要调整第n条线段使得第n条线段的起点在前n-1条线段的可行区间里。
那么我们根据ans[n]求出来另一个可行区间,这两个区间一定有交,我们枚举一下四个端点即可确定ans[n-1],
然后余弦定理求旋转角。
递归n次。

这个acos还是第一次遇到。。。我人傻了。

#include <bits/stdc++.h>
using namespace std;
typedef double db;
const db eps=1e-6;
const db pi=acos(-1);
int sign(db k){if (k>eps) return 1; else if (k<-eps) return -1; return 0;}
int cmp(db k1,db k2){return sign(k1-k2);}
struct point {
    db x,y;
    point operator + (const point &k1) const{return (point){k1.x+x,k1.y+y};}
    point operator - (const point &k1) const{return (point){x-k1.x,y-k1.y};}
    point operator * (db k1) const{return (point){x*k1,y*k1};}
    point operator / (db k1) const{return (point){x/k1,y/k1};}
    point turn(db k1){return (point){x*cos(k1)-y*sin(k1),x*sin(k1)+y*cos(k1)};}
    db abs(){return sqrt(x*x+y*y);}
    void print(){printf("%.3f %.3f\n",x,y);}
    point unit(){
        db w=abs();
        if(cmp(w,0)==0)return {0,0};
        return (point){x/w,y/w};
    }
    db getw(){return atan2(y,x);}
};
db jiao(db a,db b,db c){
    if(cmp(a,0)==0||cmp(b,0)==0)return 0;
    db s = (a*a+b*b-c*c)/2/a/b;
    if(cmp(s,1)==0)s=1;
    else if(cmp(s,-1)==0)s=-1;
    return acos(s);
}
point p[22],x;
int n;
db a[22],l[22],r[22],ans[22],delta[22],l2[22],r2[22];
bool can(db x,int i){return cmp(x,l[i])>=0&&cmp(x,r[i])<=0&&cmp(x,l2[i])>=0&&cmp(x,r2[i])<=0;}
void slove(int now){//在求第now个点
    if(now<1)return;
    //不妨对每一步求可行解
    if(cmp(a[now+1],l2[now+1])>=1&&cmp(a[now+1],r2[now+1])<=0){
        l2[now]=0;
    }else if(cmp(a[now+1],l2[now+1])==-1){
        l2[now]=l2[now+1]-a[now+1];
    }else if(cmp(a[now+1],r2[now+1])==1){
        l2[now]=a[now+1]-r2[now+1];
    }
    r2[now]=r2[now+1]+a[now+1];
    db x=0;
    if(can(l[now],now)){x=l[now];
    }else if(can(r[now],now)){x=r[now];
    }else if(can(l2[now],now)){x=l2[now];
    }else if(can(r2[now],now)){x=r2[now];}

    ans[now]=x;
    l2[now]=ans[now],r2[now]=ans[now];
    db del = jiao(ans[now],ans[now+1],a[now+1]);
    delta[now] = del;//我要绕逆时针角度
    slove(now-1);
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%lf",&a[i]);
    scanf("%lf%lf",&x.x,&x.y);
    ans[n]=x.abs();
    ans[1]=a[1];
    l[1]=a[1],r[1]=a[1];
    for(int i=2;i<=n;i++){
        if(cmp(a[i],l[i-1])>=0&&cmp(a[i],r[i-1])<=0){
            l[i]=0;
        }else if(cmp(a[i],l[i-1])==-1){
            l[i]=l[i-1]-a[i];
        }else if(cmp(a[i],r[i-1])==1){
            l[i]=a[i]-r[i-1];
        }
        r[i]=r[i-1]+a[i];
    }
    if(cmp(ans[n],r[n])>=1){
        x = x.unit()*r[n];
        if(x.abs()==0)x={r[n],0};
    }else if(cmp(ans[n],l[n])<=0){
        x = x.unit()*l[n];
        if(x.abs()==0)x={l[n],0};
    }
    p[n]=x;ans[n]=x.abs();l2[n]=ans[n],r2[n]=ans[n];
    delta[n]=x.getw();
    slove(n-1);
    for(int i=n-1;i>=1;i--)delta[i]+=delta[i+1];
    for(int i=1;i<=n;i++){
        point tmp = {ans[i],0};
        tmp.turn(delta[i]).print();
    }
}
/**

4
7 8 9 20
0 -34
2
10000 132576
-37 -9999

 */
posted @ 2019-10-26 18:57  MXang  阅读(135)  评论(0编辑  收藏  举报