• HGOI20180831 NOIP2018模拟


    input1:

    4
    4 4 4 4
    3 2 4 5
    4 5 5 5
    1 7 3 2

    output1:

    Yes
    Yes
    Yes
    No

    好的吧数学题QwQ考场上没人做出来qwq

    就是判断两个矩形能否互相放到对方里面

    后来想了想这道题怎么那么简单,判断边长不就得了吗?

    虽然想到这道题是T2但还是傻到交一个可能0分的程序上去。。。(详见说明)

    于是就有这么多代码。。。

    • 大矩形的长大于小矩形的长,宽大于小矩形的宽,这时肯定可以放得下去;
    • 大矩形的对角线小于小矩形的对角线,那么也就没有地方容下小矩形了,这时判定否;

    70pts code:

    # include <bits/stdc++.h>
    using namespace std;
    int main()
    {
        freopen("girls.in","r",stdin);
        freopen("girls.out","w",stdout);
        int n; scanf("%d",&n);
        for (int i=1;i<=n;i++) {
            int a,b,c,d;
            scanf("%d%d%d%d",&a,&b,&c,&d);
            if (a>b) swap(a,b);
            if (c>d) swap(c,d);
            if (a<=c&&b<=d) printf("Yes
    ");
            else if (c<=a&&d<=b) printf("Yes
    ");
            else printf("No
    ");
        }
        return 0;
    }

    然后70pts 

    后来发现这是有反例的qwq?

    斜着放?

    像这样:

    这样的话额。。好像小长方形略长一点好像是可以放下的qwq(其实也可以结合生活经验)

    好的吧

     这个时候我们发现并不能直接下结论。。要推倒。。

    • 当小矩形的长大于大矩形的长时,此时斜放也可能放进大矩形,所以我们进行以下计算。

    具体怎么算呢?

    放个图:

    思路:求出L1,L2验证以L1,L2构成直角三角形的斜边比y大那么就行否则不行。

    BC2=x2+y2又 CI2=a2 所以 BI2=BC2-CI2=x2+y2-a2

    所以BI=sqrt(x2+y2-a2

    由△ABF≌DCH(显然AAS)

    BF=CH=L1 而IG=CH(矩形)

    所以在GF上有 BF+BI+IG=GF 代入得 2L1+BI=EH

    所以 L1=(EH-BI)/2=(b-sqrt(x2+y2-a2))/2;

    同理可知 L2=(GH-AJ)/2=(a-sqrt(x2+y2-b2))/2;

    若Rt△CHD中有sqrt(CD)<sqrt(L12+L22)即 y2<L12+L22

    则合法否则不合法。所以有这样一个程序:

    • 大矩形的长大于小矩形的长,宽大于小矩形的宽,这时肯定可以放得下去;
    • 大矩形的对角线小于小矩形的对角线,那么也就没有地方容下小矩形了,这时判定否;
    • 当小矩形的长大于大矩形的长时,此时斜放也可能放进大矩形,所以我们进行以下计算。如上图,假如左下角的那个小三角形,L1与L2求出第三条边大于等于小矩形的宽的话,那么小矩形就可以(碰壁)的放进去。

    100pts code:

    # include <bits/stdc++.h>
    using namespace std;
    bool fun(int x,int y,int a,int b)
    //(x,y)能否放到(a,b),(长,宽)
    {
        if (x<=a&&y<=b) return true;
        if (x*x+y*y>a*a+b*b) return false;
        double L1=(b-sqrt(x*x+y*y-a*a))/2.0;
        double L2=(a-sqrt(x*x+y*y-b*b))/2.0;
        if (L1*L1+L2*L2>=(double)y*y) return true;
        else return false;
    }
    int main()
    {
        freopen("girls.in","r",stdin);
        freopen("girls.out","w",stdout);
        int T;scanf("%d",&T);
        while (T--) {
            int x,y,a,b;
            scanf("%d%d%d%d",&x,&y,&a,&b);
            if (x<y) swap(x,y);
            if (a<b) swap(a,b);
            if (fun(x,y,a,b)||fun(a,b,x,y)) printf("Yes
    ");
            else printf("No
    ");
        }
        return 0;
    }

    input1:

    5 6
    0 6 6 10 10 
    2 0 7 8 6 
    10 5 0 10 3 
    9 5 8 0 7 
    4 9 8 3 0 
    1 2 3
    1 4 1
    2 1 3
    1 4 2
    1 1 2
    2 4 1

    output1:

    6
    11

    题目意思:给出一幅完全图每次操作删一条边求两点最短路。(其中删边操作小于200)

    要求任意两点最短路显然想到floyd最快!!!

    但是要删掉一条边啊。不好办。

    考场上第一想法是那道我们做过的O(n4)的一道加一条权为0的边求最短路

    (好像是luogu2018新春模拟赛的T2)

    想强制在线。。(这是显然想法好吧,是完全图、稠密图想到dijkstra好伐)

    然后看到数据范围啦么小想一把暴力就过了吧,然后打了一个dijkstra堆优化好像是O(mn log n)

    然后愉快的发现好像要T qwq

    好的,这样以来就是想强制离线可不可以做,改删边为加边。

    (反着做)我设现在要加的边为s-->t 权为w,

    首先更新s--->t的最短路O(1)

    那么枚举两个点u和v更新这两个点的最短距离显然有3种方法

    • u--->s--->t--->v
    • u--->t---->s--->v
    • u--->v

    由于各个点最短路我是知道的了,那么这些求值就是O(1)的了加边更新复杂度为O(n2)

    有不多于200个删边操作O(n3)显然是够的,查询的话就是O(1)

    这就是离线的算法。

    考场上打的n<=40000的暴力dijkstra没有删去将就着看看。

    # include <bits/stdc++.h>
    # define INF INT_MAX/3
    # define Rint register int
    using namespace std;
    const int MAXN=205,MAXM=100005;
    struct record{
        int pre,to,w;
    }a[MAXN*MAXN];
    int e[MAXN][MAXN],n,m,tot=0,head[MAXN];
    struct qwq{
        int c,x,y;
    }q[MAXM];
    int rec[MAXN][MAXN],mp[MAXN][MAXN],ans[MAXM];
    inline int read()
    {
        int X=0,w=0; char c=0;
        while(c<'0'||c>'9') {w|=c=='-';c=getchar();}
        while(c>='0'&&c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar();
        return w?-X:X;
    }
    void adde(int u,int v,int w)
    {
        a[++tot].pre=head[u];
        a[tot].to=v;
        a[tot].w=w;
        head[u]=tot;
    }
    struct ww{
        int id,lenth;
        bool operator <(const ww a) const{
            if (lenth!=a.lenth) return lenth>a.lenth;
            else return id>a.id;
        }
    };
    priority_queue<ww> qq;
    int d[MAXN];
    bool vis[MAXN];
    inline void dijkstra(int s,int t)
    {
        memset(vis,0,sizeof(vis));
        for (int i=1;i<=n;i++) d[i]=INF;
        d[s]=0;
        ww Node; Node.id=s;Node.lenth=0;qq.push(Node);
        while (!qq.empty()) {
            ww Node=qq.top();qq.pop();
            int u=Node.id;
            if (vis[u]) continue;
            vis[u]=true;
            for (int i=head[u];i;i=a[i].pre) {
                int v=a[i].to;
                if (d[v]-a[i].w>d[u]) {
                    d[v]=d[u]+a[i].w;
                    ww N;N.id=v;N.lenth=d[v];
                    qq.push(N);
                }
            }
        }
        if (d[t]<INF) printf("%d
    ",d[t]);
        else printf("-1
    ");
    }
    void work1()
    {
        int x,y,c;
        for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
        {
            scanf("%d",&x);
            if (i==j) continue;
            adde(i,j,x);e[i][j]=tot;
        }
        for (int i=1;i<=m;i++) {
            c=read();x=read();y=read();
            if (c==2) {
                dijkstra(x,y);
                continue;
            }
            a[e[x][y]].w=INF;
        }
    }
    int main()
    {
        freopen("journey.in","r",stdin);
        freopen("journey.out","w",stdout);
        scanf("%d%d",&n,&m);
        if (m<=40000) {
            work1();
            return 0;
        }
        for (Rint i=1;i<=n;i++)
         for (Rint j=1;j<=n;j++)
          scanf("%d",&mp[i][j]),rec[i][j]=mp[i][j];
        for (Rint i=1;i<=m;i++) {
            q[i].c=read();q[i].x=read();q[i].y=read();
            if (q[i].c==1) mp[q[i].x][q[i].y]=INF;
        }
        for (Rint k=1;k<=n;k++)
         for (Rint i=1;i<=n;i++)
          for (Rint j=1;j<=n;j++)
            mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
        for (Rint i=m;i>=1;i--) {
            if (q[i].c==2) {
                  ans[++ans[0]]=mp[q[i].x][q[i].y];
                  continue;
            }
            int s=q[i].x,t=q[i].y;
            mp[s][t]=min(mp[s][t],rec[s][t]);
            for (int u=1;u<=n;u++)
            for (int v=1;v<=n;v++)
             mp[u][v]=min(min(mp[u][v],mp[u][s]+mp[s][t]+mp[t][v]),mp[u][t]+mp[t][s]+mp[s][v]);
        }
        for (Rint i=ans[0];i>=1;i--)
         if (ans[i]>=INF) printf("-1");
         else printf("%d
    ",ans[i]);
        return 0;
    }

    input1:

    5
    1 2
    2 3
    3 4
    4 5

    output1:

    1

    input2:

    8
    1 2
    1 3
    2 4
    2 5
    3 6
    3 7
    1 8

    output2:

    2

    题目意思:是在一棵树上找到两个点使各个点到这两点的最大距离最小。

    是真的不会做。。

    那么就暴力本来想打LCA的结果发现floyd更快。。

    就是暴力枚举那两个点,再枚举各个点到这两个点最小距离求最大值(就是按照题意模拟吧)

    # include <bits/stdc++.h>
    using namespace std;
    const int MAXN=2005;
    int mp[MAXN][MAXN];
    int n;
    inline int read()
    {
        int X=0,w=0; char c=0;
        while(c<'0'||c>'9') {w|=c=='-';c=getchar();}
        while(c>='0'&&c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar();
        return w?-X:X;
    }
    bool p[MAXN],vis[MAXN];
    int main()
    {
        freopen("ob.in","r",stdin);
        freopen("ob.out","w",stdout);
        scanf("%d",&n);
        for (int i=1;i<=n;i++)
         for (int j=1;j<=n;j++)
          if (i!=j) mp[i][j]=INT_MAX/3;
        for (int i=1;i<=n-1;i++) {
            int u,v;
            u=read();v=read();
            mp[u][v]=1; mp[v][u]=1;
        }
        for (int k=1;k<=n;k++)
         for (int i=1;i<=n;i++)
          for (int j=1;j<=n;j++)
           if (k!=i&&i!=j&&j!=k) mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
        int ans=INT_MAX;
        for (int t1=1;t1<=n;t1++)
         for (int t2=1;t2<=n;t2++) {
            if (t1==t2) continue;
             int Max=0;
             for (int u=1;u<=n;u++) Max=max(Max,min(mp[u][t1],mp[u][t2]));
            ans=min(ans,Max);
         }
         printf("%d
    ",ans);
        return 0;
     }

    话说考场上写了点奇怪的东西竟然没有T???

    【话说如果做出来了就会update的】

    • 60pts Floyd暴力模拟!!!(就是上面那种方法)
    • 80pts(1) 期望树是随机的,那么默认树的直径是log级别很短,直接在直径上枚举两个点O(n log2n)-O(n3)
    • 80pts(2) 考虑两个奖杯管辖范围有边界枚举一条边作为边界(u---v)u作为一棵子树,v作为一棵子树,分别求两棵树的直径求最小值O(n2
    • 100pts

    显然奖杯在树的直径上(奖杯首先要将树的直径覆盖),

    所以二分答案MID,表示从一个点扩展开去可以覆盖的范围

    然后check的时候判断这两点扩展开去染色是否存在没有被染色的点存在,

    有就是false没有就是true

     其他方法:

    • 100pts (2)奖杯在直径上,二分答案后取离直径上离端点距离答案的点,遍历 check 一遍
    • 100pts (3)随便提一个节点为根,二分答案,深度最深的节点一定要被照顾到,所以最深的点往上跳 答案层即可,和其距离答案以内的点都删掉,再做一次。 此法可以拓展到 k 个奖杯。
    • 100pts (4)在 80 分的基础上用树形 dp,记下每个点向下前三长和向上一格后不回该子树最长的路径 长度。子树内直径是前两长的和与该子树各个子树直径取 max;子树外直径是父节点向上一格 后不回该子树最长的路径长度,前两长不进入该子树的向下最长路径这三条取前两长加起来与 父节点以上的答案取 max。
    # include <bits/stdc++.h>
    # define Rint register int
    using namespace std;
    const int Root=1,MAXN=200005;
    struct rec{
        int pre,to;
    }a[MAXN<<1];
    bool col[MAXN];
    int n,dep[MAXN],line[MAXN],head[MAXN],pre[MAXN],tot=0,ans;
    void adde(int u,int v) //加边
    {
        a[++tot].pre=head[u];
        a[tot].to=v;
        head[u]=tot;
    }
    int getpts() //求出最深点并且把dep赋值为0
    {
        int Max=0,P=1;
        for (int i=1;i<=n;i++)
         if (Max<dep[i]) Max=dep[i],P=i;
        memset(dep,0,sizeof(dep));
        return P;
    }
    void getline(int u) //求树的直径到line[]里面方便计算
    {
        memset(line,0,sizeof(line));
        while (pre[u]!=-1) {
            line[++line[0]]=u;
            u=pre[u];
        }
        line[++line[0]]=u;
    }
    void dfs1(int u,int fat,int depth) //树的直径先一边任一点开始dfs到最深点s
    {
        dep[u]=depth;
        for (Rint i=head[u];i;i=a[i].pre){
            int v=a[i].to; if (v==fat) continue;
            dfs1(v,u,depth+1);
        }
    }
    void dfs2(int u,int fat,int depth) //从s开始dfs到最深点t并记录每个点是从谁(pre前驱)走过来的方便搞出line[]
    {
        pre[u]=fat; dep[u]=depth;
        for (Rint i=head[u];i;i=a[i].pre){
            int v=a[i].to; if (v==fat) continue;
            dfs2(v,u,depth+1);
        }
    }
    void draw(int u,int step,int fat) //u向外染色step步
    {
        col[u]=true; //col 是true表示染色 false没染色
        if (step==0) return;
        for (Rint i=head[u];i;i=a[i].pre){
            int v=a[i].to; if (v==fat) continue;
            draw(v,step-1,u);
        }
    }
    bool check(int MID) //判断是否可行
    {
        memset(col,false,sizeof(col));
        int Node1=line[1+MID],Node2=line[line[0]-MID]; //最深处要顾及到
        draw(Node1,MID,-1);
        draw(Node2,MID,-1);
        for (Rint i=1;i<=n;i++)
         if (!col[i]) return false;
        return true;
    }
    void ErFen() //二分答案
    {
        int l=1,r=line[0];
        while (l<=r){
            int mid=(l+r)>>1;
            if (check(mid)) r=mid-1,ans=mid;
            else l=mid+1;
        }
    }
    int main()
    {
        scanf("%d",&n);
        if (n<=2) { printf("0
    "); return 0; } //特判,不用走都能看到
        int u,v;
        for (Rint i=1;i<=n-1;i++)
         scanf("%d%d",&u,&v),adde(u,v),adde(v,u);
        dfs1(Root,-1,0); int s=getpts();
        memset(pre,0,sizeof(pre));
        dfs2(s,-1,0);    int t=getpts();
        getline(t);
        ErFen();
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    需要学习的技术
    Building wheel for uwsgi (setup.py) ... error 解决问题
    version `ZLIB_1.2.3.4‘ not found 解决方法
    module 'tensorflow' has no attribute 'space_to_depth'(已解决)
    python语法—命名元祖、偏函数
    python—set集合比较(交集、并集,差集)
    websocket接口测试
    linux根目录扩容方法
    django—问题—中文编码格式报错 、分页warning
    python—使用sorted对字典进行排序
  • 原文地址:https://www.cnblogs.com/ljc20020730/p/9565983.html
Copyright © 2020-2023  润新知