Codeforces Round #618 (Div. 2) C~E题解
Codeforces Round #618 (Div. 2)
C. Anu Has a Function
题意:定义一种函数为:f:f(x, y) = (x|y) - y
给定一个数组[a1,a2,…,an],将其定义为f(f(…f(f(a1,a2),a3),…an−1),an),改变数组元素的位置顺序,使得f(f(…f(f(a1,a2),a3),…an−1),an)的值最大。
分析:
按位分析可以发现:
| x | y | x | y - y |
|---|---|---|
| 1 | 0 | 1 |
| 0 | 0 | 0 |
| 1 | 1 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 1 |
也就是说:(x|y) - y = x & (-y)
那么f(f(…f(f(a1,a2),a3),…an−1),an) = a1 & (-a2) & (-a3) & ...... & (-an)
从上面式子可以看出答案只与a1有关,与后面(-a2)....(-an)无关
a1的选择即将所有数的二进制从最高位开始扫描,找到一个数在这个位为1,其他数在这个位均为0,这个数就是a1的选择。
///C
#include <cstdio>
#include <algorithm>
using namespace std;
int a[100005];
int cnt[35];
int main(){
int n;
scanf("%d\n", &n);
for(int i = 1; i <= n; i++){
scanf("%d", &a[i]);
for(int j = 0; j <= 30; j++){
if(a[i] & (1 << j))
cnt[j]++;
}
}
int ans = -1, sum = 0;
for(int i = 1; i <= n; i++){
int tans = 0;
for(int j = 0; j <= 30; j++){
if(a[i] & (1 << j))
if(cnt[j] == 1)
tans += 1 << j;
}
if(tans > ans){
ans = tans;
sum = i;
}
}
printf("%d ", a[sum]);
for(int i = 1; i <= n; i++){
if(i != sum)
printf("%d ", a[i]);
}
return 0;
} D. Aerodynamic
题意:将给定的图形P通过平移(平移所得的图形必须包含原点),最后能达到的轮廓即为T,如果T和P相似,则输出YES,否则输出NO。
分析:画图可以知道T必定为中心对称图形,那么问题就转化为p是否为中心对称图形。
关于判断中心对称的思想:
首先,只有偶数个结点才可能成为中心对称图形,其次:
所有节点的x之和 / 有多少对节点 = 一对对应坐标的x之和
///D
#include <cstdio>
#include <map>
using namespace std;
typedef long long ll;
map<pair<int, int>, int>mp;
const int N = 3e5 + 7;
ll x[N], y[N];
int main(){
int n;
scanf("%d", &n);
ll sum1 = 0, sum2 = 0;
if(n % 2 == 1){
printf("NO\n");
return 0;
}
for(int i = 1; i <= n; i++){
scanf("%lld%lld", &x[i], &y[i]);
sum1 += x[i];
sum2 += y[i];
mp[make_pair(x[i], y[i])] = 1;
}
for(int i = 1; i <= n; i++){
if(mp[make_pair(sum1 / (n / 2) - x[i], sum2 / (n / 2) - y[i])] == 0){
printf("NO\n");
return 0;
}
}
printf("YES\n");
return 0;
} E.Water Balance
题意:给你一个数组,你可以选定一个区间,使得区间内的每个元素变成该区间元素的平均值,可以多次选定区间,让最终得到的数组的字典序最小。
分析:思考一下可以知道,当后一个数比前一个数小的时候,将其合并,所得结果能使得前一个数减小。
所谓字典序小,就是要让越前面的数尽可能的越小。
///E
#include <cstdio>
const int N = 1e6 + 5;
double a[N];
double b[N], l[N];
int main(){
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%lf", &a[i]);
}
int ans = 0;
for(int i = 1; i <= n; i++){
b[++ans] = a[i];
l[ans] = 1;
while(ans > 1 && b[ans] < b[ans - 1]){
b[ans - 1] = (b[ans - 1] * l[ans - 1] + b[ans] * l[ans]) / (l[ans] + l[ans - 1]);
l[ans - 1] += l[ans];
ans--;
}
}
for(int i = 1; i <= ans; i++){//ans为分为多少段
for(int j = 1; j <= l[i]; j++)
printf("%.9lf\n", b[i]);
}
return 0;
} 


