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:观察发现, 可以得出,如果某一位最后为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';
}
}
}