bzoj5328: [Sdoi2018]物理实验

果然我还是太菜了,爆了一天才过。。。。隔壁肉丝都不知道喊了多少句哎╮(╯▽╰)╭我又A了什么傻逼题(然鹅就是wf和国集的题QWQ)

其实这个题就是个裸题,但是我就是不会。。。

这个题第一步就是明显的旋转坐标系(不会的百度),注意要先平移坐标系再旋转

然后问题就变成x轴上下有一些线段,考虑覆盖长度为L的一段区间,看看区间内最接近x轴的线段的长度和(也可以直接按题意理解,好像更好懂)

线段是斜着的很难搞,但是假如覆盖了l~r的区间,那么也可以通过三角函数搞出线段长度

可以先弄一个类似离散化的东西,我的意思是每个线段的左右端点的x坐标为断点,相邻x坐标之间可以看成一段(大概就是这样不懂评论我)

主要问题在处理出每一段最接近x轴的线段是那一条,假如搞定了这个东西,我们可以正反枚举每个段,然后能要段就要,再加上下一个段的一部分更新答案,这个双指针扫一下就好

考虑按端点的x坐标上扫描线,对于线段有一个关键的性质,就是线段不相交,这里隐含着这么一个东西:假如线段u的左端点的x坐标较小,线段v的左端点在线段u的上方/下方,直到u被删除线段的上下关系都是不变的,否则线段就相交了

换句话说,不相交满足对于在任意一条线段的左右端点x坐标框住的区间中,任意一条线段和这一条线段的上下关系不变

那么有这个东西就可以做了,用set维护一下上方最下的线段和下方最上的线段即可

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<set>
using namespace std;
typedef long double LD;
const int _=1e2;
const int maxn=1e4+_;
const LD eps=1e-12;
LD sqr(LD x){return x*x;}
int n;

struct point{LD x,y; point(){} point(LD X,LD Y){x=X,y=Y;}};
LD getdis(point p1,point p2){return sqrt(sqr(p1.x-p2.x)+sqr(p1.y-p2.y));}
LD slope(point p1,point p2){return (p2.y-p1.y)/(p2.x-p1.x);}
LD multi(point p1,point p2,point p0)
{
    LD x1,y1,x2,y2;
    x1=p1.x-p0.x;
    y1=p1.y-p0.y;
    x2=p2.x-p0.x;
    y2=p2.y-p0.y;
    return x1*y2-x2*y1;
}

//------------------------------------------------def-----------------------------------------------------

struct board
{
    point A,B;
    LD g;//长度变化的比值 1/cos
    void getg(){g=getdis(A,B)/fabs(A.x-B.x);}
}b[maxn];bool cmp(board b1,board b2){return b1.A.y<b2.A.y;}
bool bbbbcmp(board b1,board b2){return b1.A.x<b2.A.x;}

LD co,si;
point rot(point p){return point(p.x*co-p.y*si,p.y*co+p.x*si);}
void rotate()
{
    LD d=getdis(b[n+1].A,b[n+1].B);
    co=fabs(b[n+1].A.x-b[n+1].B.x)/d;
    si=fabs(b[n+1].A.y-b[n+1].B.y)/d;
    if(b[n+1].A.x<b[n+1].B.x&&b[n+1].A.y<b[n+1].B.y)si=-si;

    for(int i=1;i<=n;i++)
    {
        b[i].A.x-=b[n+1].A.x,b[i].A.y-=b[n+1].A.y;
        b[i].B.x-=b[n+1].A.x,b[i].B.y-=b[n+1].A.y;

        b[i].A=rot(b[i].A);
        b[i].B=rot(b[i].B);
        if(b[i].A.x>b[i].B.x)swap(b[i].A,b[i].B);
        b[i].getg();

//        printf("%.10Lf %.10Lf %.10Lf %.10Lf\n",b[i].A.x,b[i].A.y,b[i].B.x,b[i].B.y);
    }
}

//---------------------------------------------------rotate-------------------------------------------------

LD xx[2*maxn];int xlen;
bool xx_cmp(LD x1,LD x2){return x1<x2;}
int up[2*maxn],dp[2*maxn];//xx[i]~xx[i-1]这一段被那条线段覆盖着 

struct seg
{
    int id;
    seg(){} seg(int ID){id=ID;}
    friend bool operator <(seg s1,seg s2)
    {
        int x=s1.id,y=s2.id;
        if(x<y)return multi(b[x].B,b[y].A,b[x].A)>0;
        else   return multi(b[y].B,b[x].A,b[y].A)<0;
    }
    friend bool operator >(seg s1,seg s2)
    {
        int x=s1.id,y=s2.id;
        if(x<y)return multi(b[x].B,b[y].A,b[x].A)<0;
        else   return multi(b[y].B,b[x].A,b[y].A)>0;
    }
};set< seg,less<seg> >us;set< seg,greater<seg> >ds;

struct qq{int op,p;seg s; qq(){} qq(int OP,int P,seg S){op=OP,p=P,s=S;}}uq[2*maxn],dq[2*maxn];int uqlen,dqlen;
bool qqqqcmp(qq q1,qq q2){return q1.p==q2.p?q1.op>q2.op:q1.p<q2.p;}

int lb(LD d)
{
    int l=1,r=xlen;
    while(l<=r)
    {
        int mid=(l+r)/2;
        if(fabs(xx[mid]-d)<=eps)return mid;
        if(xx[mid]>d)r=mid-1;
        else l=mid+1;
    }
}
void cover(int l1,int r1,int l2,int r2)
{
    sort(b+l1,b+r1+1,bbbbcmp);
    sort(b+l2,b+r2+1,bbbbcmp);
    uqlen=dqlen=0;
    for(int i=l1;i<=r1;i++)
    {
        uq[++uqlen]=qq( 1,lb(b[i].A.x)+1,seg(i));
        uq[++uqlen]=qq(-1,lb(b[i].B.x),seg(i));
    }
    for(int i=l2;i<=r2;i++)
    {
        dq[++dqlen]=qq( 1,lb(b[i].A.x)+1,seg(i));
        dq[++dqlen]=qq(-1,lb(b[i].B.x),seg(i));
    }

    us.clear(),ds.clear();
    sort(uq+1,uq+uqlen+1,qqqqcmp);
    sort(dq+1,dq+dqlen+1,qqqqcmp);
    int utp=1,dtp=1;
    for(int i=1;i<=xlen;i++)
    {
        while(utp<=uqlen&&uq[utp].p==i&&uq[utp].op==1)us.insert(uq[utp].s),utp++;
        while(dtp<=dqlen&&dq[dtp].p==i&&dq[dtp].op==1)ds.insert(dq[dtp].s),dtp++;

        if(!us.empty())up[i]=(*us.begin()).id; else up[i]=-1;
        if(!ds.empty())dp[i]=(*ds.begin()).id; else dp[i]=-1;

        while(utp<=uqlen&&uq[utp].p==i&&uq[utp].op==-1)us.erase(uq[utp].s),utp++;
        while(dtp<=dqlen&&dq[dtp].p==i&&dq[dtp].op==-1)ds.erase(dq[dtp].s),dtp++;
    }
}

//-----------------------------------------------cover------------------------------------------------------

int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n+1;i++)
            scanf("%Lf%Lf%Lf%Lf",&b[i].A.x,&b[i].A.y,&b[i].B.x,&b[i].B.y);
        scanf("%Lf",&b[n+1].g);
        if(b[n+1].A.x>b[n+1].B.x)swap(b[n+1].A,b[n+1].B);
        rotate();

        //....step1.......

        int pp=n+1; sort(b+1,b+n+1,cmp);
        xlen=0;
        for(int i=1;i<=n;i++)
        {
            if(b[i].A.y>0&&pp==n+1)pp=i;
            xx[++xlen]=b[i].A.x;
            xx[++xlen]=b[i].B.x;
        }
        sort(xx+1,xx+xlen+1);
        int tp=1;
        for(int j=2;j<=xlen;j++)
            if(fabs(xx[j]-xx[tp])>eps)xx[++tp]=xx[j];
        xlen=tp;
        cover(pp,n,1,pp-1);

        //....step2.......

        LD ans=0,sum=0;
        int j=1;
        for(int i=2;i<=xlen;i++)
        {
            while(j<xlen&&(xx[j+1]-xx[i-1])<=b[n+1].g)
            {
                j++;
                if(up[j]!=-1)sum+=(xx[j]-xx[j-1])*b[up[j]].g;
                if(dp[j]!=-1)sum+=(xx[j]-xx[j-1])*b[dp[j]].g;
            }
            LD num=0;
            if(j<xlen)
            {
                if(up[j+1]!=-1)num+=min(xx[j+1]-xx[j],b[n+1].g-(xx[j]-xx[i-1]))*b[up[j+1]].g;
                if(dp[j+1]!=-1)num+=min(xx[j+1]-xx[j],b[n+1].g-(xx[j]-xx[i-1]))*b[dp[j+1]].g;
            }
            ans=max(ans,sum+num);
            if(up[i]!=-1)sum-=(xx[i]-xx[i-1])*b[up[i]].g;
            if(dp[i]!=-1)sum-=(xx[i]-xx[i-1])*b[dp[i]].g;

//            printf("%.10Lf %.10Lf %.10Lf\n",xx[i]-xx[i-1],b[up[i]].g,b[dp[i]].g);
        }
        j=xlen;sum=0;
        for(int i=xlen;i>1;i--)
        {
            while(j>1&&(xx[i]-xx[j-1])<=b[n+1].g)
            {
                if(up[j]!=-1)sum+=(xx[j]-xx[j-1])*b[up[j]].g;
                if(dp[j]!=-1)sum+=(xx[j]-xx[j-1])*b[dp[j]].g;
                j--;
            }
            LD num=0;
            if(j>1)
            {
                if(up[j]!=-1)num+=min(xx[j]-xx[j-1],b[n+1].g-(xx[i]-xx[j]))*b[up[j]].g;
                if(dp[j]!=-1)num+=min(xx[j]-xx[j-1],b[n+1].g-(xx[i]-xx[j]))*b[dp[j]].g;
            }
            ans=max(ans,sum+num);
            if(up[i]!=-1)sum-=(xx[i]-xx[i-1])*b[up[i]].g;
            if(dp[i]!=-1)sum-=(xx[i]-xx[i-1])*b[dp[i]].g;
        }

        printf("%.10Lf\n",ans);
//        break;
        //....step3.......
    }

    return 0;
}

原文地址:https://www.cnblogs.com/AKCqhzdy/p/10561320.html

时间: 2024-08-06 01:22:48

bzoj5328: [Sdoi2018]物理实验的相关文章

[SDOI2018]物理实验 set,扫描线,旋转坐标系

[SDOI2018]物理实验 set,扫描线,旋转坐标系 链接 loj 思路 先将导轨移到原点,然后旋转坐标系,参考博客. 然后分线段,每段的贡献(三角函数值)求出来,用自己喜欢的平衡树,我选set. 显然答案的一端是小线段的端点. 然后扫描线求出最大的ans. 代码 #include <bits/stdc++.h> using namespace std; const int N=1e5+7; int n,op[N]; long double X[N][2],Y[N][2],x[2],y[2

腾讯课堂的物理实验(2017计蒜客初赛第三场)

A题 在腾讯课堂的物理课上,进行了一个有趣的物理实验. 在一个长度为 LL 米的光滑轨道上,小车 A 在 00 时刻以 1\mathrm{m/s}1m/s 的速度从左端出发向右运动,小车 B 在 tt 时刻以 1\mathrm{m/s}1m/s 的速度从右端出发向左运动,两个小车的质量相等.假设所有碰撞都是弹性碰撞,也就是当两个小车相向碰撞时,他们各自会以原来的速度向相反的方向运动:小车和轨道两端发生碰撞时,小车会以原速度向反方向运动. 试求出 TT 时刻的时候,两个小车相距多远. 输入格式 输

北航物理实验

99级物理实验试题 1. 测量电压表内阻的线路如图所示.为电阻箱,为稳压电源,其内阻可忽略不计.实验测得一组不同值时的电压表读数(见下表).试用一元线性归纳法(不要求计算相关系数和不确定度)求出.   20.0 50.0 100.0 200.0 300.0 400.0   2.80 2.72 2.60 2.38 2.20 2.04 (一元线性回归的计算公式为:) 解: 令,则(由于的有效数字多,精度高,故用做) , ,.   1 2 3 4 5 6 平均   2.8 2.72 2.6 2.33

「SDOI2018」物理实验

题目大意: 这题不好描述,直接看原题吧…… 题解: 很无脑的题……就是卡精度+难写.代码能力还是太差了. 其实可以直接用long double肝过去.但我的代码似乎太丑了,以至于跑得奇慢无比. 代码: #include "bits/stdc++.h" using namespace std; inline int read() { int s=0,k=1;char ch=getchar(); while (ch<'0'|ch>'9') ch=='-'?k=-1:0,ch=g

[基础物理实验]轮换表以及仿真实验情况

SDOI2018

SD的题有点反人类啊... d1t1[SDOI2018]物理实验 感觉比较好想但不太好写,写了一半弃了 d1t2[SDOI2018]战略游戏 建出圆方树,每次建虚树,答案就是虚树上的原点个数减去询问的点数. 1 //Achen 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cstdlib> 6 #include<vector> 7 #includ

利用“远程教育资源”实施物理教学的教学经验

正安县位于贵州省与重庆市交界的边远贫困山区,这里交通落后,教师外出学习和培训的机会很少,因此导致正安的教育比较落后,远程教育资源开通后,这里的教师和学生可以运用远程教育进行学习和运用,我作为一名正安县中等职业学校物理教师也不例外,通过这几年的教学实践活动,总结出几方面运用"远程教育资源"进行"物理教学"的教学经验: 一.运用"远程教育资源"进行"物理教学"培训 基础教育教学改革的要求中大力推进信息技术在教学过程中的普遍应用,促

英国《物理世界》杂志评选出世界十大物理学家

英国<物理世界>杂志评选出了人类有史以来10位最伟大的物理学家.他们是:1.爱因斯坦: 2.牛顿: 3.麦克斯韦: 4.玻尔: 5.海森伯格: 6.伽利略: 7.费曼: 8.狄拉克: 9.薛定鄂: 10.卢瑟福. 这十大物理学家无疑是我们学习的榜样,他们的学习.生活和工作是很值得我们研究的.本文拟就十大物理学家的基本情况做一比较分析. 1出生与概况 爱因斯坦:1879年3月14日出生于德国南部符腾堡的乌尔姆城,父亲经营一家小型工厂,家庭经济较困难,几次搬家.6岁,母亲开始教他拉小提琴. 190

关于做实验

做物理实验, 要多观察,多细心观察,不要漏过每个细节,要多思考,想想为什么, 会对结果产生什么样的影响,千万不能机械的做实验! 观察真的很重要!! 机械结构设计的稳定性也很重要! 充分的利用编程实现辅助的小工具,进行大量实验,采集大量数据! 这样最后,稳定的结果才有意义!