zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    使用 Dockerfile 定制镜像
    UVA 10298 Power Strings 字符串的幂(KMP,最小循环节)
    UVA 11090 Going in Cycle!! 环平均权值(bellman-ford,spfa,二分)
    LeetCode Best Time to Buy and Sell Stock 买卖股票的最佳时机 (DP)
    LeetCode Number of Islands 岛的数量(DFS,BFS)
    LeetCode Triangle 三角形(最短路)
    LeetCode Swap Nodes in Pairs 交换结点对(单链表)
    LeetCode Find Minimum in Rotated Sorted Array 旋转序列找最小值(二分查找)
    HDU 5312 Sequence (规律题)
    LeetCode Letter Combinations of a Phone Number 电话号码组合
  • 原文地址:https://www.cnblogs.com/charles1999/p/12362807.html
Copyright © 2011-2022 走看看