• Codeforces Round #624 (Div. 3)【ABCDEF】(题解)


    涵盖知识点:树状数组、后缀数组、二叉树构造。

    比赛链接:

    http://codeforces.com/contest/1311

    A:Add Odd or Subtract Even

    题意:给定ab两个数,每次操作可以将a增加任意一个奇数或是减少任意一个偶数。问最少几次使两个数字相等。

    题解:

      1)a=b:0次。

      2)a>b:奇偶性相同1次,不同2次。

      3)a<b:奇偶性不同1次,相同2次。

    Accept Code:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 int main(){
     5     int t;
     6     cin>>t;
     7     while(t--){
     8         int a,b;
     9         cin>>a>>b;
    10         if(a==b){
    11             cout<<"0
    ";
    12             continue;
    13         }
    14         if(a>b){
    15             if(a%2==b%2){
    16                 cout<<"1
    ";
    17                 continue;
    18             }else{
    19                 cout<<"2
    ";
    20                 continue;
    21             }
    22         }
    23         if(a<b){
    24             if(a%2==b%2){
    25                 cout<<"2
    ";
    26                 continue;
    27             }else{
    28                 cout<<"1
    ";
    29                 continue;
    30             }
    31         }
    32     }
    33     return 0;
    34 }

    B:WeirdSort

    题意:给定两个数组a和p。问是否能够通过交换a[pi]a[pi+1]使得a数组从小到大排序。

    题解:通过数组p划分n个区间,顺序扫描每个区间进行内部排序,最后check一下整个数组是否完全排序。

    Accept Code:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=110;
     4 int a[maxn];
     5 bool p[maxn];
     6 int main(){
     7     int t;
     8     cin>>t;
     9     while(t--){
    10         memset(p,false,sizeof p);
    11         int n,m;
    12         cin>>n>>m;
    13         for(int i=1;i<=n;i++){
    14             cin>>a[i];
    15         }
    16         for(int i=1;i<=m;i++){
    17             int pos;
    18             cin>>pos;
    19             p[pos]=true;
    20         }
    21         for(int i=1;i<=n;i++){
    22             if(!p[i])continue;
    23             int j=i;
    24             while(j<=n&&p[j])
    25                 j++;
    26             sort(a+i,a+j+1);
    27             i=j;
    28         }
    29         bool flag=true;
    30         for(int i=1;i<n;i++){
    31             flag&=a[i]<=a[i+1];
    32         }
    33         puts(flag?"YES":"NO");
    34     }
    35     return 0;
    36 }

    C:Perform the Combo

    题意:给定一个小写字母字符串和一个数字数组。顺序输入字符串但是碰到数字数组中所含数字时必须从头开始输入。问26个小写字母各输入了多少次。

    题解:利用后缀数组维护区间输入次数,最后扫描一次即可。

    Accept Code:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=2e5+10;
     4 int num[26],nxt[maxn];
     5 
     6 int main(){
     7     int t;
     8     cin>>t;
     9     while(t--){
    10         memset(nxt,0,sizeof nxt);
    11         memset(num,0,sizeof num);
    12         int n,m;
    13         cin>>n>>m;
    14         string s;
    15         cin>>s;
    16         for(int i=0;i<m;i++){
    17             int pos;
    18             cin>>pos;
    19             nxt[pos-1]++;
    20         }
    21         for(int i=n-1;i>0;i--){
    22             nxt[i-1]+=nxt[i];
    23         }
    24         for(int i=0;i<n;i++){
    25             num[s[i]-'a']+=nxt[i]+1;
    26         }
    27         for(int i=0;i<26;i++){
    28             cout<<num[i]<<" ";
    29         }
    30         cout<<"
    ";
    31     }
    32     return 0;
    33 }

    D:Three Integers

    题意:给abc三个数,每次操作可以使任意一个数字+1或者-1.问最少操作几次使得c被b整除,b被a整除。

    题解:根据题意显然a的变化范围只能在[1,2a](如果大于2a就可以把a变为1,显然更优)。b同理。所以我们可以对于a范围内的每一个A,遍历b范围里所有A的倍数B,来确定一个C使得|C-c|最小。

    那么问题就转化为C的求法。不难得出C的取值会在中得出。取较小值即可。

    Accept Code:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int inf=0x3f3f3f3f;
     4 int main(){
     5     int t;
     6     cin>>t;
     7     while(t--){
     8         int a,b,c,ans=inf;
     9         cin>>a>>b>>c;
    10         int A=-1,B=-1,C=-1;
    11         for(int i=1;i<=2*a;i++){
    12             for(int j=i;j<=2*b;j+=i){
    13                 for(int k=0;k<=1;k++){
    14                     int l=j*(c/j)+k*j;
    15                     int res=abs(i-a)+abs(j-b)+abs(l-c);
    16                     if(res<ans){
    17                         ans=res;
    18                         A=i,B=j,C=l;
    19                     }
    20                 }
    21             }
    22         }
    23         cout<<ans<<"
    "<<A<<" "<<B<<" "<<C<<"
    ";
    24     }
    25     return 0;
    26 }

    E:Construct the Binary Tree

    题意:给定n个结点,要求构造出一棵二叉树使得所有节点距离根节点的距离之和为d。

    题解:两种解法:1.从一条链不断将子节点上移。2.从一个完全二叉树开始退化。

    这里采用第二种。每层节点选择一个代表并标记。后从大到小将未标记的节点作为本层代表的子节点。若当层代表还有其他子节点,继续下移。直到移动到最后一层后自己作为新一层的代表并标记即可。

    Accept Code:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int inf=0x3f3f3f3f,maxn=5010;
     4 int pre[maxn],dep[maxn],node[maxn];
     5 bool flag[maxn];
     6 int main(){
     7     int t;
     8     cin>>t;
     9     while(t--){
    10         memset(flag,false,sizeof flag);
    11         int n,d;
    12         cin>>n>>d;
    13         int maxd=0;
    14         node[0]=1;
    15         for(int i=2;i<=n;i++){
    16             pre[i]=i/2;
    17             dep[i]=dep[pre[i]]+1;
    18             d-=dep[i];
    19             maxd=max(maxd,dep[i]);
    20         }
    21         if(d<0){
    22             cout<<"NO
    ";
    23             continue;
    24         }
    25         int idx=n;
    26         while(idx){
    27             node[dep[idx]]=idx;
    28             flag[idx]=true;
    29             idx=pre[idx];
    30         }
    31         for(int i=n;i>=1;i--){
    32             if(flag[i])continue;
    33             int tmp=maxd;
    34             while(dep[pre[i]]<tmp&&d){
    35                 pre[i]=node[dep[i]];
    36                 dep[i]++;
    37                 if(dep[i]>maxd){
    38                     maxd++;
    39                     node[maxd]=i;
    40                     flag[i]=1;
    41                 }
    42                 d--;
    43             }
    44         }
    45         if(d){
    46             cout<<"NO
    ";
    47             continue;
    48         }
    49         cout<<"YES
    ";
    50         for(int i=2;i<=n;i++){
    51             cout<<pre[i]<<" ";
    52         }
    53         cout<<"
    ";
    54     }
    55     return 0;
    56 }

    F:Moving Points

    题意:给定n个点的初始坐标和速度。定义dis(i,j)为点i和点j在任意时刻的距离的最小值。求1~n之间所有点对的dis(i,j)的和。

    题解:分两种情况。

      1)若xi<xj且vi>vj,则dis(i,j)=0(即一定有某一时刻两点相遇)。

      2)others,dis(i,j)即为初始两点的距离。

    即仅others的情况对答案有贡献。

    所以只要将所有点按照坐标从小到大排序,另开一个数组存所有的速度,排序并去重。利用二分查找速度数组得出小于当前点速度的点个数。开两个树状数组,一个cnt维护速度小于v的个数,一个sum维护速度小于v的x之和。从左向右扫描一遍所有的点,每次加上x*cnt-sum,并将状态加入树状数组中维护即可。当然也可以使用线段树等其他数据结构维护。

    Accept Code:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int maxn = 2e5 + 10;
     5 ll c[maxn][2], b[maxn], ans, len;
     6 int n;
     7 inline int lowbit(int x){return x&(-x);}
     8 struct Node{
     9     int x,v;
    10     bool operator <(Node &b)const{
    11         return x<b.x;
    12     }
    13 } a[maxn];
    14 
    15 void add(int x, int val){
    16     while (x <= n)
    17         c[x][0]++, c[x][1] += val, x += lowbit(x);
    18 }
    19 
    20 ll query(int x, int k){
    21     ll res = 0;
    22     while (x)
    23         res += c[x][k], x -= lowbit(x);
    24     return res;
    25 }
    26 
    27 int main(){
    28     cin>>n;
    29     ans = 0, len = 0;
    30     for(int i=1;i<=n;i++)
    31         cin>>a[i].x;
    32     for(int i=1;i<=n;i++){
    33         cin>>a[i].v;
    34         b[++len] = a[i].v;
    35     }
    36     sort(a + 1, a + 1 + n);
    37     sort(b + 1, b + 1 + len);
    38     len = unique(b + 1, b + 1 + len) - b - 1;
    39     for(int i=1;i<=n;i++){
    40         int idx = lower_bound(b + 1, b + 1 + len, a[i].v) - b;
    41         ans += a[i].x * query(idx, 0) - query(idx, 1);
    42         //cout<<a[i].x<<" "<<query(idx,0)<<" "<<query(idx,1)<<endl;
    43         add(idx, a[i].x);
    44     }
    45     cout<<ans<<"
    ";
    46     return 0;
    47 }
  • 相关阅读:
    练习
    圆形时钟
    鼠标经过改变颜色
    Java基础知识精华部分(个人总结)
    Java随机数总结
    java 获取随机数字的三种方法
    网站开发人员应该知道的61件事
    人人都该了解的十大算法
    String 字符串
    面向对象 JAVA代码
  • 原文地址:https://www.cnblogs.com/charles1999/p/12362807.html
Copyright © 2020-2023  润新知