• CF1092 D & E —— 思路+单调栈,树的直径


    题目:https://codeforces.com/contest/1092/problem/D1

    https://codeforces.com/contest/1092/problem/D2

    https://codeforces.com/contest/1092/problem/E

    很有趣的题;

    对于D1,首先发现两种砖的放法和高度的奇偶性有关(!);

    而竖着放的砖不改变一列的奇偶性,也就是确定一列的奇偶性后,它的高度是可以任意的,那么我们就不用考虑实际高度的问题了;

    然后发现,如果两列奇偶性相同的列相邻了,那么它们就“无敌”了,可以变成任意高度;

    而两列可以合并,只能是它们相邻且奇偶性相同;

    这就很像两组括号序列啊!奇数是 (),偶数是 [],那么整个序列就是 (, ), [, ] 相间的;

    只要栈顶能完成一个匹配,就弹栈表示这两列“无敌”了;

    所以最后要是栈里没有元素或只剩下一个元素,序列就是合法的,否则不合法;

    这么简单就做完了!

    代码如下:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int const xn=2e5+5;
    int n,sta[xn],top;
    int rd()
    {
      int ret=0,f=1; char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return f?ret:-ret;
    }
    int main()
    {
      n=rd();
      for(int i=1,x;i<=n;i++)
        {
          x=rd();
          if(top&&(x&1)==(sta[top]&1))top--;
          else sta[++top]=x;
        }
      if(top<=1)puts("YES");
      else puts("NO");
      return 0;
    }
    D1

    对于D2,只能放横着的砖;

    那就更简单了,每次先填满最低的一段,如果其长度是奇数就不合法了,否则就和旁边的合并成一段;

    这个过程可以用单调栈维护。

    代码如下:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int const xn=2e5+5;
    int n,sta[xn],top,len[xn],a[xn];
    int rd()
    {
      int ret=0,f=1; char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return f?ret:-ret;
    }
    int main()
    {
      n=rd();
      for(int i=1;i<=n;i++)a[i]=rd(); 
      for(int i=1,l,j;i<=n;i=j+1)
        {
          j=i; l=0;
          while(a[i]==a[j+1])j++;
          while(top&&a[i]>sta[top])
        {
          if(len[top]&1){puts("NO"); return 0;}
          l=len[top]; top--;
          if(top&&sta[top]<a[i])len[top]+=l;
          else break;
        }
          while(top&&sta[top]==a[i])l+=len[top--];
          sta[++top]=a[i]; len[top]=l+(j-i+1);
          //printf("sta[%d]=%d len=%d
    ",top,sta[top],len[top]);
        }
      int l=0;
      while(top>1)
        {
          l+=len[top--];
          if(l&1){puts("NO"); return 0;}
        }
      puts("YES");
      return 0;
    }
    D2

    E题要最小化连通块合成的树的直径,还要输出连边方案;

    结论就是找到所有连通块(小树)的直径中点,最大的直径的中点连接所有其他中点;

    想想果然很有道理,因为这样其实最终的直径还是最大连通块的直径,除非有几个连通块一样都是最大;

    而其他连法都可能让直径更大;

    所以只需要找直径中点即可,看了看提交记录,发现可以写得很优美,就是 dfs 同时找直径端点、长度和中点;

    因为如果从一端 dfs 到另一端,那么中点一定在路径上,返回的时候记录一下即可;

    然后注意特别判断有两个或三个一样大的最大连通块;

    直径的性质要好好利用。

    代码如下:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #define pb push_back
    using namespace std;
    int const xn=1005;
    int n,hd[xn],ct,to[xn<<1],nxt[xn<<1],dis[xn],mx,d;
    int vis[xn];
    struct N{
      int x,d;
      N(int x=0,int d=0):x(x),d(d) {}
      bool operator < (const N &y) const
      {return d<y.d;}
    };
    vector<N>v;
    int rd()
    {
      int ret=0,f=1; char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return f?ret:-ret;
    }
    void add(int x,int y){to[++ct]=y; nxt[ct]=hd[x]; hd[x]=ct;}
    void dfs(int x)
    {
      vis[x]=1;
      if(dis[x]>mx)mx=dis[x],d=x;
      for(int i=hd[x],u;i;i=nxt[i])
        if(vis[u=to[i]]!=1)dis[u]=dis[x]+1,dfs(u);
    }
    bool dfsx(int x)
    {
      vis[x]=2; bool ret=0;
      if(dis[x]>mx)mx=dis[x],ret=1;
      for(int i=hd[x],u;i;i=nxt[i])
        if(vis[u=to[i]]!=2)
          {
        dis[u]=dis[x]+1;
        if(dfsx(u))ret=1;
          }
      if(ret&&dis[x]==mx/2)d=x;//
      return ret;
    }
    int main()
    {
      n=rd(); int m=rd(); int ans=0;
      for(int i=1,x,y;i<=m;i++)x=rd(),y=rd(),add(x,y),add(y,x);
      for(int i=1;i<=n;i++)
        if(!vis[i])
          {
        dis[i]=0; mx=-1; dfs(i);
        dis[d]=0; mx=-1; dfsx(d); 
        ans=max(ans,mx); v.pb(N(d,mx));
          }
      sort(v.begin(),v.end()); int siz=v.size();
      if(siz>1)
        {
          ans=max(ans,(v[siz-1].d+1)/2+(v[siz-2].d+1)/2+1);//
          if(siz>2)ans=max(ans,(v[siz-2].d+1)/2+(v[siz-3].d+1)/2+2);//
        }
      printf("%d
    ",ans);
      int u=v[siz-1].x;
      for(int i=0;i<siz-1;i++)
        printf("%d %d
    ",u,v[i].x);
      return 0;
    }
    E
  • 相关阅读:
    selenium python (十五)控制滚动条操作
    selenium python (十四)上传文件的处理
    selenium python (十三)对于分页的处理
    selenium python (十二)下拉框的处理
    selenium python (十一)alert/confirm/prompt的处理(js中的弹出框)
    selenium python (十)浏览器多窗口处理
    selenium python (九)对话框处理
    selenium python (八)定位frame中的对象
    企业分布式微服务云SpringCloud SpringBoot mybatis (三) 服务消费者(Feign)
    企业分布式微服务云SpringCloud SpringBoot mybatis (二)服务消费者(rest+ribbon)
  • 原文地址:https://www.cnblogs.com/Zinn/p/10159357.html
Copyright © 2020-2023  润新知