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;
}
全部评论

相关推荐

11-27 12:43
已编辑
门头沟学院 C++
点赞 评论 收藏
分享
11-28 17:48
中山大学 C++
点赞 评论 收藏
分享
评论
1
收藏
分享
牛客网
牛客企业服务