[BZOJ 3553/3554/3562/3564/3565/3566][SHTSC/HBOI 2014]解题报告

来源:互联网 发布:python打包gui 编辑:程序博客网 时间:2024/05/29 19:48

Day1

Problem 1 信号增幅仪(BZOJ 3564)

http://www.lydsy.com:808/JudgeOnline/problem.php?id=3564

思路:如果裸着做会很麻烦,所以我们需要进行一个简单的预处理。和增幅仪的旋转角度相反,将所有点顺时针旋转a度,然后将所有点的横坐标缩小p倍。然后就可以套用最小圆覆盖的模板做了,这里我用的是随机增量法。

#include <iostream>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <algorithm>#include <cmath> #define PI 3.14159265358979323846#define MAXN 510000#define EPS (1E-20) using namespace std; struct Point{    double x,y;    Point(double xx=0,double yy=0)    {        x=xx;        y=yy;    }    Point operator-(Point a)    {        return Point(x-a.x,y-a.y);    }    Point operator+(Point a)    {        return Point(x+a.x,y+a.y);    }    double operator*(Point a)    {        return x*a.y-y*a.x;    }    Point operator*(double t)    {        return Point(x*t,y*t);    }    Point operator/(double t)    {        return Point(x/t,y/t);    }    Point rotate(double ang) //绕原点顺时针旋转ang度    {        return Point(x*cos(ang)+y*sin(ang),-x*sin(ang)+y*cos(ang));    }    Point verl()    {        return Point(-y,x);    }}dots[MAXN]; int n; int dcmp(double x) //x>0返回1,x<0返回-1,x==0返回0{    if(fabs(x)<EPS) return 0;    if(x>EPS) return 1;    return -1;} double dist(Point a,Point b) //求点a到点b距离{    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));} Point cross(Point a,Point b,Point c,Point d) //求向量ab叉乘向量cd{    double s1=(d-a)*(c-a);    double s2=(c-b)*(d-b);    return (a*s2+b*s1)/(s1+s2);} Point cal(Point A,Point B,Point C){    Point ret;    double a1=B.x-A.x,b1=B.y-A.y,c1=(a1*a1+b1*b1)/2;    double a2=C.x-A.x,b2=C.y-A.y,c2=(a2*a2+b2*b2)/2;    double d=a1*b2-a2*b1;    ret.x=A.x+(c1*b2-c2*b1)/d;    ret.y=A.y+(a1*c2-a2*c1)/d;    return ret;} int main(){    double ang,scale;    scanf("%d",&n);    for(int i=1;i<=n;i++)        scanf("%lf%lf",&dots[i].x,&dots[i].y);    scanf("%lf%lf",&ang,&scale);    ang=ang/180*PI;    for(int i=1;i<=n;i++)    {        dots[i]=dots[i].rotate(ang);        dots[i].x/=scale;    }    double r=0; //r=三角形的外接圆半径    Point c=dots[1];    for(int i=2;i<=n;i++)    {        if(dist(dots[i],c)>r+EPS)        {            c=dots[i];            r=0;            for(int j=1;j<i;j++)            {                if(dist(dots[j],c)>r+EPS)                {                    c=(dots[i]+dots[j])/2;                    r=dist(dots[j],c);                    for(int k=1;k<j;k++)                    {                        if(dist(dots[k],c)>r+EPS)                        {                            c=cal(dots[i],dots[j],dots[k]);                            r=dist(dots[i],c);                        }                    }                }            }        }    }    printf("%.3lf\n",r);    return 0;}

Problem 2 概率充电器(BZOJ 3566)

http://www.lydsy.com:808/JudgeOnline/problem.php?id=3566

思路:树形DP,首先我们需要知道一个概率的公式,对于两个相互独立的事件A、B,P(A+B)=P(A)+P(B)-P(AB)。每个点都给它们的所有儿子贡献了一部分概率,第一次DFS时,我们需要求出每个点u的每个儿子v的充电概率P'(v)=P(v)+[P(u)*p(edge)]-[P(u)*p(edge)]*P(v)。由于第一次DFS时会混进重复计算的概率(因为父亲节点给本节点的概率不能被算进本节点给儿子节点的概率),所以要再进行一次DFS,去除掉重复的概率。

#include <iostream>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <algorithm>#include <cmath> #define MAXN 1001000#define EPS (1E-6) using namespace std; struct edge{    int u,v,next;    double p; //边的导电概率}edges[MAXN]; int head[MAXN],nCount=0;double pNode[MAXN]; //直接通电的概率double f[MAXN];double ans=0; void AddEdge(int U,int V,double P){    edges[++nCount].u=U;    edges[nCount].v=V;    edges[nCount].p=P;    edges[nCount].next=head[U];    head[U]=nCount;} void dfs1(int u,int fa) //从点u开始dfs,u的父亲是fa{    for(int p=head[u];p!=-1;p=edges[p].next)    {        int v=edges[p].v;        if(v==fa) continue;        dfs1(v,u);        pNode[u]=pNode[u]+pNode[v]*edges[p].p-pNode[u]*edges[p].p*pNode[v];    }} bool dcmp(double a){    return fabs(a-0)<EPS;} void dfs2(int u,int fa){    ans+=f[u];    for(int p=head[u];p!=-1;p=edges[p].next)    {        int v=edges[p].v;        if(v==fa) continue;        double tmp=(1-pNode[v]*edges[p].p);        if(dcmp(tmp)) //tmp==0            f[v]=1.0;        else        {            double y=(double)(f[u]-pNode[v]*edges[p].p)/(double)(1-pNode[v]*edges[p].p);            f[v]=pNode[v]+y*edges[p].p-pNode[v]*y*edges[p].p;        }        dfs2(v,u);    }} int main(){    int n;    scanf("%d",&n);    memset(head,-1,sizeof(head));    for(int i=1;i<n;i++)    {        int u,v,p;        scanf("%d%d%d",&u,&v,&p);        AddEdge(u,v,(double)p/(double)100);        AddEdge(v,u,(double)p/(double)100);    }    for(int i=1;i<=n;i++)    {        scanf("%lf",&pNode[i]);        pNode[i]/=100;    }    dfs1(1,-1);    f[1]=pNode[1];    dfs2(1,-1);    printf("%.6f\n",ans);    return 0;}

Problem 3 超能粒子炮(BZOJ 3565)

http://www.lydsy.com:808/JudgeOnline/problem.php?id=3565

Day2

Problem 1 神奇化合物(BZOJ 3562)

http://www.lydsy.com:808/JudgeOnline/problem.php?id=3562

Problem 2 三叉神经树(BZOJ 3553)

http://www.lydsy.com:808/JudgeOnline/problem.php?id=3553

Problem 3 神秘金字塔(BZOJ 3554)

http://www.lydsy.com:808/JudgeOnline/problem.php?id=3554


0 0
原创粉丝点击