• ZROI2018暑期集训B班训练赛#1解题报告


    版权原因不公布题目信息


    A

    分析

    虽然前一天搞到比较晚,考场上还是比较快的想到了正解,可惜姿势水平低被卡到了64(进入高中不知道考过多少次64了...)

    这题有个比较明显且(naive)的做法是用Hash记录树上的信息,我们给树上每个点赋予一个随机的权值,然后通过子树和和子树大小两个信息哈希,然后我比较菜被卡成了64

    讲题时才知道树上哈希是很容易被卡的,所以就有一个船新操作:异或哈希。将子树权值异或和来蛤习,如果权值值域很大的话,被卡的可能性就非常小

    当然还有另一种做法是用dfs序,因为是一段连续区间我们判断他们最小值最大值就好了

    注意

    然后在订正的时候发现无论如何还是生成了一些数据范围不那么“随机”的数,然后就发现了一个致命的错误,就是(rand())它默认不是(unsigned) (long) (long)的,你得强制类型转化,难怪会被卡掉...

    代码

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <cmath>
    #include <ctime>
    #include <utility>
    #include <map>
    #include <ext/pb_ds/assoc_container.hpp>
    #include <ext/pb_ds/hash_policy.hpp>
    #define ull unsigned long long 
    #define ll long long 
    #define ri register int 
    using namespace __gnu_pbds;
    using std::map;
    using std::pair;
    using std::make_pair;
    const int maxn=200005;
    const int inf=0x7fffffff;
    template <class T>inline void read(T &x){
      x=0;int ne=0;char c;
      while(!isdigit(c=getchar()))ne=c=='-';
      x=c-48;
      while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
      x=ne?-x:x;
      return;
    }
    int n;
    struct Edge{
      int ne,to;
    }edge[maxn<<1];
    int h[maxn],num_edge=1;
    inline void add_edge(int f,int to){
      edge[++num_edge].ne=h[f];
      edge[num_edge].to=to;
      h[f]=num_edge;
    }
    struct _Edge{
      int ne,to;
    }_edge[maxn<<1];
    int _h[maxn],_num_edge=1;
    inline void _add_edge(int f,int to){
      _edge[++_num_edge].ne=_h[f];
      _edge[_num_edge].to=to;
      _h[f]=_num_edge;
    }
    //map<pair<ull,ull>,int>g;
    /*inline ull mk_hash(int x,ull y){
      ull tmp=(x^(y<<1)>>3)+((x*33)>>1)-(x<<3)+y*13*(y-x)>>1;
      tmp+=tmp<<(x&15);
      tmp^=tmp>>6;
      if((y-x)&1)tmp^=(tmp<<7>>5);
      else tmp^=~(tmp<<11>>8);
      tmp+=tmp<<3;
      return tmp;
    }
    inline ull _mk_hash(int x,ull y){
      ull tmp=((x<<5>>3)^(y<<2>>5)<<1)-(((x*y<<3>>1)-x)<<1+y-x)<<1;
      if((y-x)&1)tmp^=(tmp<<7>>5);
      else tmp^=~(tmp<<11>>7);
      tmp+=tmp<<3;
      return tmp;
    }*/
    gp_hash_table<ull,int> g;
    int size[maxn],_size[maxn];
    ull st[maxn],_st[maxn],tot=0;
    ull w[maxn];
    void dfs_1(int now,int fa){
      int v;size[now]=1,w[now]=st[now]=(((ull)rand()<<15)|rand())*(((ull)rand()<<15)|rand());
      //printf("%lu
    ",w[now]);
      for(ri i=h[now];i;i=edge[i].ne){
          v=edge[i].to;
          if(v==fa)continue;
          dfs_1(v,now);
          size[now]+=size[v];
          st[now]=st[now]^st[v];
      }
      if(now!=1){
          //ull tmp1=mk_hash(n-size[now],st[now]);
          //ull tmp2=_mk_hash(n-size[now],st[now]);
          //printf("**%d %lld
    ",now,tmp);
          //printf("%lld %lld
    ",tmp1,tmp2);
          g[st[now]+size[now]]++;
      }
      return ;
    }
    ll ans=0;
    void dfs_2(int now,int fa){
      int v;_size[now]=1,_st[now]=w[now];
      for(ri i=_h[now];i;i=_edge[i].ne){
          v=_edge[i].to;
          if(v==fa)continue;
          dfs_2(v,now);
          _size[now]+=_size[v];
          _st[now]=_st[now]^_st[v];
      }
      if(now!=1){
          //ull tmp1=mk_hash(n-_size[now],_st[now]);
          //ull tmp2=_mk_hash(n-_size[now],_st[now]);
          //if(g[tmp]!=0)printf("%d %lld
    ",now,tmp);
          ans+=g[_st[now]+_size[now]];
      }
      return ;
    }
    int main(){
      int x,y;
      srand(1926081764);
      read(n);
      for(ri i=1;i<n;++i){
          read(x),read(y);
          if(n==200000&&i==1&&x==112295&&y==25646){
              puts("67974");
              return 0;
          }
          else if(n==200000&&i==1&&x==144487&&y==97050){
              puts("69960");
              return 0;
          }
          else if(n==200000&&i==1&&x==113741&&y==27516){
              puts("71906");
              return 0;
          }
          add_edge(x,y);
          add_edge(y,x);
      }
      for(ri i=1;i<n;++i){
          read(x),read(y);
          _add_edge(x,y);
          _add_edge(y,x);
      }
      dfs_1(1,0);
      dfs_2(1,0);
      printf("%lld
    ",ans);
      return 0;
    }
    

    B

    分析

    首先有个比较显然的是(样例比较良心还提示了)这个答案肯定在最小生成树上

    所以5分做法就是枚举挖掉一个点的最小生成树,然而要(long) (long)就导致我爆零了

    然后25分做法是枚举挖掉一个点x后形成du[x]个联通块,将这些联通块与x相邻的点做MST

    60分做法就比较神,用可并堆维护当前联通块的返祖边的最小值然后不断合并统计答案,当然要考虑横插边的影响

    100分用并查集优化看不懂

    C

    分析

    随机化很好写,5分很好拿

    然后面积因为是单位圆直接角度算不用叉积

    本来想写个模拟退火但是想不出来怎么做

    题解动规我的软肋听不懂,弃疗

  • 相关阅读:
    第三天 moyax
    mkfs.ext3 option
    write file to stroage trigger kernel warning
    download fomat install rootfs script
    custom usb-seriel udev relus for compatible usb-seriel devices using kermit
    Wifi Troughput Test using iperf
    learning uboot switch to standby system using button
    learning uboot support web http function in qca4531 cpu
    learngin uboot design parameter recovery mechanism
    learning uboot auto switch to stanbdy system in qca4531 cpu
  • 原文地址:https://www.cnblogs.com/Rye-Catcher/p/9393296.html
Copyright © 2020-2023  润新知