Codeforces Round 1035 (Div. 2)题解 (折线可达定理?)

A. Add or XOR

题目大意:给两个整数a, b。两种操作: op1 : 给a加一,代价为x;op2:a异或1,代价为y。问a到b的最低代价,不能则输出-1.

hint1: a异或1,当a为偶数给a带来加1的贡献,a为奇数,给a带来减1的贡献。

hint2: a不能凭借多次异或1,减很多1。

hint3: a > b 且 a ^ 1 != b时无法到达b

解决方法:如果x < y, 直接无脑操作一就行。反之,交替进行操作一和操作二,直到达到b。

code:

void solve() {
    int a, b, x, y;
    cin >> a >> b >> x >> y;
    if(a > b && (a ^ 1) != b) {
        cout << "-1\n";
        return;
    }
    if(a > b) {
        cout << y << '\n';
        return;
    }
    {
        if(x < y) cout << (b - a) * x << '\n';
        else {
            if(a & 1) {
                cout << ((b - a) / 2) * (x + y) + ((b - a) % 2) * x << '\n';
            } else cout << ((b - a) / 2) * (x + y) + ((b - a) % 2) * y << '\n';
        }
    }
}

B. Line Segments

题目大意:给p, q两个点,分别为起点和终点,给你n个正整数a1, a2, ... an,从p出发,每次走一条直线,距离为ai,问能否到达q。

hint1:从起点出发,走n条折线的距离的范围是多少。

hint2:如果p, q距离在范围之外,则无法到达,反之必定到达。

hint3:显然最长距离为sum。

hint4:最短距离为多少?

解决方法:mindist = max(0,2⋅amax​−sum)。

proof:

  • 如果最长线段 amax很长,其余线段长度不够把它“折回来”,那么最短距离是 2amax−S。

  • 如果其他线段够长(S−amax≥amax​),那么可以折叠成一个闭合多边形,最短距离就是 0(终点可以回到起点)。

code:

void solve() {
    int n;
    cin >> n;
    int px, py, qx, qy;
    cin >> px >> py >> qx >> qy;
    vector<int> a(n);
    for(int &x : a) cin >> x;
    sort(a.begin(), a.end());
    reverse(a.begin(), a.end());
    int l, r;
    l = a[0], r = a[0];
    for(int i = 1; i < n; ++i) {
        l -= a[i];
        r += a[i];
    }
    
    if(l < 0) l = 0;
    int dd = (px - qx) * (px - qx) + (py - qy) * (py - qy);
    if(l * l > dd || r * r < dd ) {
        cout << "NO\n";
    } else cout << "YES\n";
}

C. A Good Problem

题目大意:给定n, l, r, k,要你构造一个序列,满足序列的每一个数的异或等于没一个数的与,并且每一个数都在l和r之间。如果有多种情况,要求字典序最小的情况,输出这个序列的第k个数。

hint1:观察发现,a_1 \oplus a_2\oplus a_3 .... \oplus a_n = a_1\And a_2\And a_3\And .... a_n 可以得出,如果某一位最后为1的话,那必然,所有位都是1并且n为奇数。

hint2:由hint1的发现,我们可以得出n为奇数时的答案:全取l即可,此时直接输出l,这样我们的讨论范围缩小了一半。

hint3:现在来讨论n为偶数的情况,显然最后结果不可能有位为1,所以你构造的n个数中,不能满足存在一位有奇数个1,这样会导致异或为1。同样的不能满足有位全部为1,这样会导致与为1.

hint4:由hint3的发现,我们可以特判n为2时的情况,此时无法构造合法序列。

结合上面的观察

解决方法:我们选中的序列的数中,不能满足其位数相等。如果满足的话,最高位就全为1了,此时与hint3的发现矛盾。所以构造方法就很清晰了,找出比l多一位的最小数即minn = 10..0这种,如果minn > r, 无法构造,否则合法,为了满足最小情况,我们选取2个minn,剩下的全为l, 即l l l l .... minn minn。

code:

void solve() {
    int n, l, r, k;
    cin >> n >> l >> r >> k;
    if(n & 1) {
        cout << l << '\n';
        return;
    } else {
        int cnt1 = 0;
        int temp = l;
        while(temp) {
            cnt1++;
            temp /= 2;
        }
        int minn = 1LL << cnt1;
     //   cerr << minn << '\n';
        if(r < minn) {
            cout << "-1\n";
            return;
        }
        if(n == 2) {
            cout << "-1\n";
            return;
        }
        if(k <= n - 2) cout << l << '\n';
        else {
           cout << minn << '\n'; 
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值