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

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

比赛链接:

http://codeforces.com/contest/1311

A:Add Odd or Subtract Even

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

题解:

  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\n";
12             continue;
13         }
14         if(a>b){
15             if(a%2==b%2){
16                 cout<<"1\n";
17                 continue;
18             }else{
19                 cout<<"2\n";
20                 continue;
21             }
22         }
23         if(a<b){
24             if(a%2==b%2){
25                 cout<<"2\n";
26                 continue;
27             }else{
28                 cout<<"1\n";
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<<"\n";
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<<"\n"<<A<<" "<<B<<" "<<C<<"\n";
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\n";
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\n";
47             continue;
48         }
49         cout<<"YES\n";
50         for(int i=2;i<=n;i++){
51             cout<<pre[i]<<" ";
52         }
53         cout<<"\n";
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<<"\n";
46     return 0;
47 }

猜你喜欢

转载自www.cnblogs.com/charles1999/p/12362807.html