AtCoder Regular Contest 139 赛时记录
小掉了 8 分
退役前最后一场 AT 了/ll,好可惜没能上分
A - Trailing Zeros
直接从前向后模拟计算即可。
设计算到了第 \(i\) 个,上一个是 \(a_{i-1}\),那就是求一个满足 \(2^{t_i} + k 2^{t_i+1} > a_{i-1}\) 的最小的 \(k\)。
随便计算一下就行。
signed main() {
n = read();
for(int i = 1; i <= n; ++i) b[i] = read();
for(int i = 1; i <= n; ++i) {
int fir = 1ll << b[i];
int add = 1ll << (b[i] + 1);
int lst = a[i - 1];
int cnt = (lst - fir - 1) / add + 1;
if(fir > lst) cnt = 0;
a[i] = fir + add * cnt;
if(a[i] == a[i - 1]) a[i] += add;
}
cout << a[n] << "\n";
return 0;
}
B - Make N
发现三个操作不好做,如果让它变成两个操作就好做了。
我们讲三个操作分别叫做一操作,二操作,三操作
首先特判出一操作比二操作或者三操作优或者都优的情况。
然后,考虑按照 \(A,B\) 和 \(\sqrt {n}\) 的大小关心进行分讨。
设 \(A > B\),如果 \(A > \sqrt n\),我们可以暴力枚举用几次 \(A\),然后直接算剩下的贡献,对所有值取个 \(\min\)。
否则,我们考虑枚举有几次 \(1\) 操作,显然这个只需要枚举到 \(\max \{A,B\}\) 就好。也是 \(\sqrt n\) 级别。
然后我们确定了 \(A,B\) 要组成一个什么数,这个东西我们可以用 \(\text{exgcd}\) 算一下合法解,因为随着其中一个解的增大,花费的变化是单调的,所以我们取一下两个极端的贡献就好。这个东西是洛谷上的模板题。
然后就做完了,剩下的应该是亿些细节问题。
#include<bits/stdc++.h>
#define LL long long
#define int long long
#define orz cout << "tyy YYDS!!!\n"
using namespace std;
const int MAXN = 2e5 + 10;
const int INF = 1e9 + 7;
const int mod = 998244353;
int T, n, A, B, X, Y, Z;
int ans;
int read() {
int s = 0, f = 0; char ch = getchar();
while(!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while(isdigit(ch)) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
int x, y;
int Exgcd(int a, int b, int &x, int &y) {
if(!b) { x = 1, y = 0; return a; }
int d = Exgcd(b, a % b, x, y);
int t = x;
x = y, y = t - a / b * y;
return d;
}
int Solve(int m) {
if(!m) return 0;
x = 0, y = 0;
int a = A, b = B, c = m;
int ans = m * X;
if(m % A == 0) ans = min(ans, m / A * Y);
if(m % B == 0) ans = min(ans, m / B * Z);
int d = Exgcd(a, b, x, y);
if(c % d) return ans;
else {
int p = b / d, q = a / d, k;
x *= c / d, y *= c / d;
if(x < 0) k = ((-x) / p) + 1, x += p * k, y -= q * k;
if(x >= 0) k = (x - 1) / p, x -= p * k, y += q * k;
if(y > 0) {
int tmp = x, del = c / d;
ans = min(ans, (tmp * Y + (c - tmp * A) / B * Z));
tmp = ((y - 1) % q + 1);
ans = min(ans, (tmp * Z + (c - tmp * B) / A * Y));
// tmp = (x + (y - 1) / q * p);
// ans = min(ans, del * (tmp * Y + (d - tmp * A) / B * Z));
// tmp = y;
// ans = min(ans, del * (tmp * Z + (d - tmp * B) / A * Y));
} else {
return ans;
}
}
return ans;
}
void Main() {
n = read(), A = read(), B = read(), X = read(), Y = read(), Z = read();
if(Y - A * X >= 0 && Z - B * X >= 0) {
printf("%lld\n", n * X);
} else if(Y - A * X >= 0) {
printf("%lld\n", n / B * Z + n % B * X);
} else if(Z - B * X >= 0) {
printf("%lld\n", n / A * Y + n % A * X);
} else {
if(A < B) swap(A, B), swap(Y, Z);
int lim = 100000;
if(A > lim) {
ans = n * X;
for(int i = 0; i * A <= n; ++i) {
int lst = n - i * A;
ans = min(ans, i * Y + lst / B * Z + lst % B * X);
}
printf("%lld\n", ans);
} else {
// assert(0);
ans = n * X;
for(int i = 0, M = min(n, max(A, B)); i <= M; ++i) {
ans = min(ans, i * X + Solve(n - i));
}
printf("%lld\n", ans);
}
}
}
signed main() {
T = read();
while(T--) Main();
return 0;
}