zoukankan      html  css  js  c++  java
  • Atcoder Grand Contest 048 解题报告 (A-D)

    Pro A atcoder<S

    • 题意:给定字符串 (s) ,每次只能交换 (s) 中的相邻两个字符,求最小的交换次数使得 (s>) 'atcoder' 。如果无解输出 -1 。多组数据。

    • 数据范围:(Tleq 100,|s|leq 10^3)

    • 做法:

      ​ 首先判掉无解( (s) 中全为 (a) )和已经满足条件的情况。在 (s) 中找到第一个不是 (a) 的字符,设其为 (x) ,若 (x>t) ,那么直接将 (x) 移到 (t) 的位置;否则移到 (a) 的位置。 可以证明这样是最优的(分类讨论以下即可)。

    • 代码:

      #include <bits/stdc++.h>
      const int N=1e3+5;
      using namespace std;
      const char g[]={'a','t','c','o','d','e','r',''};
      char s[N];
      int  l;
      bool cant(){
          for(int i=0;i<l;++i)
              if(s[i]!='a') return false;
          return true;
      }
      bool done(){
          for(int i=0;i<min(l,7);++i)
              if(s[i]>g[i]) return true;
              else if(s[i]<g[i]) return false;
          return l>7;
      }
      void solve(){
          l=strlen(s);
          if(cant()) {puts("-1");return;}
          if(done()) {puts("0"); return;}
          for(int i=0;i<l;++i){
              if(s[i]=='a') continue;
              if(s[i]<='t') {printf("%d
      ",i);break;}
              else {printf("%d
      ",i-1);break;}
          }
      }
      int main(){
       
          int T;scanf("%d",&T);
          while(T--)
              scanf("%s",s),solve();
          return 0;
      }
      

    Pro B Bracket Score

    • 题意:给定 (n) 个变量,每个变量可以是 ()[] 中的一种。变量 (i)() 中的一种时有 (a_i) 贡献,否则有 (b_i) 贡献。当 (n) 个变量组成的字符串为合法字符串时,求最大的 (n) 个变量的贡献和。

    • 数据范围:(nleq 10^5)(n) 是偶数

    • 做法:

      ​ 假设最后有 (k) 个位置是 [] ,分别为 (x_1,x_2,cdots,x_k)

      ​ 我们假设 ((x_1,x_2),cdots,(x_{k-1},x_k)) 配对且对于每一对配对关系恒有 (x_{pre}<x_{suf})(x_2-x_1-1) 必然是偶数,即 (x_1)(x_2) 的奇偶性不同。同理,那么 (x_1,x_2,cdots,x_k)(k) 个数中必然恰好有 (frac{k}{2}) 个奇数, (frac{k}{2}) 个偶数。 实际上,恰好半奇半偶也正是 (x_1,x_2,cdots,x_k) 合法的充分条件。我们可以通过构造方案来证明:

      • 我们一定可以找到一个奇数 (x_i) 和一个偶数 (x_j) 满足两者之间再无 (x)
      • 我们可以将 (x_i)(x_j) 配对并消去,这时 (x) 序列仍然满足半奇半偶的性质。
      • 重复上述两步即可。

      ​ 问题转化为找到一种 (x_1,x_2,cdots,x_k) 满足半奇半偶的使得贡献最大的方案。假设选择 () 视作选 (0)[] 视作选 (1) ,实际上,每个 (x_1,x_2,cdots,x_k) 满足半奇半偶的方案都对应着一种选 (frac{n}{2})(0)(frac{n}{2})(1) 的方案——这是一种“双射”关系。为什么呢?

      • 假设在某一种选 (0) 的位置为半奇半偶的方案下我们选了 (c_0)(0)(c_1)(1)(c_0+c_1=1)
      • (0) 的位置是半奇半偶的同时 (1) 的位置也必然是半奇半偶。
      • 我们将偶数位全部取反。此时 (0) 的个数为 (c_0-frac{c_0}{2}+frac{c_1}{2}=frac{n}{2}) 。正好。

      ​ 问题转化为找到一种选择 (frac{n}{2})(0)(frac{n}{2})(1) 使得贡献最大的方案。先把 (b_i) 全部选择了,再把 (a_i-b_i) 排序后选择前 (frac{n}{2}) 大即可。当然,在这之前要记住在偶数位交换 (a,b)

    • 代码:

      const int N=1e5+5;
      using namespace std;
      long long n,ans;
      long long a[N],b[N];
      int main(){
      
          r(n);
          for(int i=1;i<=n;++i) r(a[i]);
          for(int i=1;i<=n;++i) r(b[i]);
          for(int i=2;i<=n;i+=2) swap(a[i],b[i]);
          for(int i=1;i<=n;++i) ans+=a[i],b[i]-=a[i];
          sort(b+1,b+n+1,greater<int>() );
          for(int i=1;i<=n/2;++i)
              ans+=b[i];
          w(ans);
          return 0;
      }
      

    Pro C Penguin Skating

    • 题意:有 (n) 只企鹅, (m) 个广场,初始时每只企鹅在一个广场上,且任意时刻一个广场上只有 (1) 只企鹅。你可以让某只企鹅向左滑或者向右滑。若让企鹅 A 向左滑,当 A 的左边没有企鹅时,它会滑倒广场 (1) ;否则假设在 A 左边距离 A 最近的企鹅在广场 (x) ,那么他就会滑到 (x+1) 。向右滑同理。给定 (n) 个企鹅的初始位置以及目标位置,问从初始位置变成目标位置的最少次数。无解输出 -1

    • 数据范围:(nleq 10^5,mleq 10^9)

    • 做法:

      ​ 设 ({a}) 表示企鹅的初始位置, ({b}) 表示目标位置。设 (a_0=0,a_{n+1}=m+1,d_i=a_i-a_{i-1}-1) ,也就是记录企鹅两两之间的距离。再设 (b_0=0,b_{n+1}=m+1,e_i=b_i-b_{i-1}-1) 。当 (forall iin [1,n+1] ext{ s.t. } d_i=e_i) 时,由于初始/结束位置均确定,且两两之间差值也确定,那么实际上原序列也就确定相同了。每次滑动企鹅,实际上就是 (d_{i+1 ext{ or }i-1}-=d_i,d_i=0) 的变换。贪心凑出来每一项 (e_i) 即可。

    • 代码:

      const int N=1e5+5;
      using namespace std;
      int n,L;
      long long a[N],b[N];
      int main(){
      
          r(n),r(L);
          for(int i=1;i<=n;++i) r(a[i]);
          for(int i=1;i<=n;++i) r(b[i]);
          a[n+1]=L+1,b[n+1]=L+1;
          for(int i=n+1;i>=1;--i)
              a[i]=a[i]-a[i-1]-1,b[i]=b[i]-b[i-1]-1;
          long long ans=0,j=1,st=1;
          for(int i=1;i<=n+1;++i){
              if(!b[i]) continue;
              while(!a[j]) ++j;st=j;
              long long cur=0; 
              while(cur<b[i]&&j<=n+1) cur+=a[j++];
              if(cur!=b[i]) {puts("-1");return 0;}
              ans+=max(0ll,j-1-i)+max(0ll,i-st);
          }
          w(ans);
          return 0;
      }
      

    Pro D Pocky Game

    • 题意:有 (n) 堆石子,两个玩家轮流丢石子。1 号玩家每次只能从最左边的石子堆丢,2 号玩家每次只能从最右边的石子堆丢。每次可以在当前堆中丢弃任意个石子。无法操作的人输。给定初始的石子序列 ({a}) ,判定谁能赢。

    • 数据范围:(nleq 10^3,a_ileq 10^9)

    • 做法:

      ​ 首先有一个性质要把握:

      • 一个人每次要么拿一个,要么拿一堆。因为拿一个后的决策范围包含了拿 (k(kin(1,a_i))) 个的决策范围。

      ​ 有了这个性质后,设 one[L][R] 表示目前只有 ([L,R]) 这些石子堆,(1) 号先手时,(a_L) 至少为多少才能让(1) 号必胜。同理设 two[L][R]

      • (a_R<two[L+1][R]) 时。无论第 (L) 堆石子有多少个, 1 号直接取完就赢了。所以 (one[L][R]=1)
      • (a_Rge two[L+1][R]) 时。双方肯定都会希望自己先把对方耗尽,所以均会一个一个取。假设第 (L) 堆有 (x) 个石子。当 1 号取到第 (L) 堆只剩 (one[L][R-1]-1) 个时,2 号必然一把将第 (R) 堆全取完;当 2 号取到第 (R) 堆只剩 (two[L+1][R]-1) 个时,1 号必然一把将第 (L) 堆全取完。 所以可得

      [x-one[L][R-1]+1>a_R-two[L+1][R]+1\ x>a_R-two[L+1][R]+one[L][R-1] ]

      ​ 所以 (x) 的最小值,也就是 (one[L][R]=a_R-two[L+1][R]+one[L][R-1]) 。求 two[][] 的过程类似。我们可以在 (mathcal{O}(n^2)) 的时间内解决此题。

    • 代码:

      const int N=1e3+5;
      using namespace std;
      int n;
      long long a[N],L[N][N],R[N][N];
      void solve(){
          r(n);
          for(int i=1;i<=n;++i)
              r(a[i]),L[i][i]=R[i][i]=1;
          for(int k=2;k<=n;++k)
          for(int i=1;i+k-1<=n;++i){
              int j=i+k-1;
              if(a[j]<R[i+1][j]) L[i][j]=1;
              else L[i][j]=a[j]-R[i+1][j]+L[i][j-1]+1;
              if(a[i]<L[i][j-1]) R[i][j]=1;
              else R[i][j]=a[i]-L[i][j-1]+R[i+1][j]+1;
          }
          puts(a[1]>=L[1][n]?"First":"Second");
      }
      int main(){
      
          int T;r(T);
          while(T--)
              solve();
          return 0;
      }
      
  • 相关阅读:
    数字化工厂仿真系统-易景空间数字孪生工厂
    会议小程序-智能会议助手在会务系统中的优势
    商场室内地图制作-商场导航-智慧商业综合体
    室内定位室内导航到底能带来什么?
    医院导航系统-智慧医院室内导航-院内导航系统
    室内地图制作-首款实时室内绘制室内地图-3D室内地图
    城市综合三维管网管理-城市三维GIS管线系统-易景地图三维管线地图制作平台
    如何制作好看的室内地图-室内电子地图-在线制作室内地图
    jQuery ui中sortable draggable droppable的使用
    综合CSS3 transition、transform、animation写的一个动画导航
  • 原文地址:https://www.cnblogs.com/parauni-blog/p/13844606.html
Copyright © 2011-2022 走看看