20170712训练赛比赛总结

A

反思

  • 虽然 AC 却花了 70 多分钟。
  • 我没有把问题想得透彻就开始敲代码 2
  • 没有意义的二分

思考流程

  • 发现题目的限制条件提示条件
    • 限制条件
      • 两点间的边权为三维坐标中的最小值。
      • 求最小生成树。
    • 提示条件
      • 我们可以把边都找出来有 3n 条边
      • 分析一下有些的边是无效的
      • 我们可以从这样一维的情况考虑
  • 分析一下我们发现对于一维的情况考虑,有效的边即为按 X 排序后每个相邻的两个点。
  • 证明一下:
    • 1234
    • 对于这样的三个点我们如果要连边 1,3 肯定是不优的,还不如以相同的代价来连 1,2 2,3
    • 同理我们可以把这样的性质利用起来,造 3n 条边来造最小生成树即可。
    • #include<bits/stdc++.h>
      using namespace std;
      typedef long long ll;
      const int M=1e5+5;
      struct P{int x,i;}X[M],Y[M],Z[M];
      struct E{
          int x,y,c;
          bool operator<(const E&A)const{
              return c<A.c;
          }
      }G[M*30];
      bool cmp(P A,P B){return A.x<B.x;}
      int n,fa[M],num;
      int find(int x){
          if(x==fa[x])return x;
          return fa[x]=find(fa[x]);
      }
      ll solve(){
          ll ans=0;
          int res=n-1;
          for(int i=1;i<=n;i++)fa[i]=i;
          for(int i=1;i<=num;i++){
              int x=G[i].x,y=G[i].y,c=G[i].c;
              if(find(x)==find(y))continue;
              else{
                  fa[find(x)]=find(y);
                  res--;
                  ans+=c;
                  if(!res)return ans;
              }
          }
          if(res)return -1;
      }
      int main(){
          scanf("%d",&n);
          for(int i=1;i<=n;++i){
              scanf("%d %d %d",&X[i].x,&Y[i].x,&Z[i].x);
              Y[i].i=Z[i].i=X[i].i=i;
          }
          sort(X+1,X+1+n,cmp);
          sort(Y+1,Y+1+n,cmp);
          sort(Z+1,Z+1+n,cmp);
          for(int i=1;i<n;i++)
              G[++num]=(E){X[i].i,X[i+1].i,X[i+1].x-X[i].x};  
          for(int i=1;i<n;i++)
              G[++num]=(E){Y[i].i,Y[i+1].i,Y[i+1].x-Y[i].x};  
          for(int i=1;i<n;i++)
              G[++num]=(E){Z[i].i,Z[i+1].i,Z[i+1].x-Z[i].x};  
          sort(G+1,G+1+num);
          ll ans=solve();
          printf("%lld",ans);
          return 0;
      }

      B

      反思

      • 怎么简单的模拟题没有AC太不应该了!!!!!!
      • 我没有把模拟的方法和复杂度想得透彻就开始敲代码 3

      思考流程

      • 没有什么可以说的。我们直接可以算出每个人个座位的距离,把它排序即可。
      #include<bits/stdc++.h>
      using namespace std;
      const int M=50*50+5;
      char str[M][M];
      bool mark[M];
      int num_a,num_b,num,cnt[M],dis[M],n,m,ans;
      struct P{
          int x,y;
          int operator+(const P&A)const{
              return (A.x-x)*(A.x-x)+(A.y-y)*(A.y-y);     
          }
      }A[M],B[M];
      struct E{
          int a,b,c;
          bool operator <(const E &A)const{return c<A.c;}
      }G[M*M];
      int main(){
          memset(dis,63,sizeof(dis));
          scanf("%d %d",&n,&m);
          for(int i=0;i<n;i++)scanf("%s",str[i]);
          for(int i=0;i<n;i++)for(int j=0;j<m;j++){
              if(str[i][j]=='X')A[++num_a]=(P){i,j};
              if(str[i][j]=='L')B[++num_b]=(P){i,j};
          }
      
          for(int i=1;i<=num_a;i++)for(int j=1;j<=num_b;j++)G[++num]=(E){i,j,A[i]+B[j]};
          sort(G+1,G+num+1);
      
          for(int i=1;i<=num;i++){
              int a=G[i].a,b=G[i].b,c=G[i].c; 
              if(mark[a]||dis[b]<c)continue;
              dis[b]=c;mark[a]=1;cnt[b]++;
          }
          for(int i=1;i<=num_b;i++)if(cnt[i]>1)ans++;
          printf("%d\n",ans);
          return 0;
      }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值