涵盖知识点:树状数组、后缀数组、二叉树构造。
比赛链接:
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 }