Codeforces Global Round 27
写在前面
比赛地址:https://codeforces.com/contest/2035。
前期犯唐 C 不会呃呃,后面 E 会了然而跑去写什么狗屁三分似掉了也没救回来。
本来想着一场上橙的,这下又掉分了哈哈。
厌学中。
A 签到
发现受到影响的位置仅有三种:
- 在第 \(r\) 行,\(c+1\sim m\) 列的,左移一位;
- 在第 \(r+1\sim n\) 行,第 1 列的,移动到上一行最后;
- 在第 \(r+1\sim n\) 行,第 \(2\sim m\) 列的,左移一位。
三种位置的贡献求和即可。
//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
//=============================================================
//=============================================================
//=============================================================
int main() {
//freopen("1.txt", "r", stdin);
std::ios::sync_with_stdio(0), std::cin.tie(0);
int T; std::cin >> T;
while (T --) {
int n, m, r, c; std::cin >> n >> m >> r >> c;
LL ans = 0;
ans += 1ll * (m - c);
ans += 1ll * (n - r) * (m - 1 + 1);
ans += 1ll * (n - r) * 1 * (m - 1);
std::cout << ans << "\n";
}
return 0;
}
B 结论
显然仅需考虑模 66 为 0。
一个显然的想法是先构造为全 3 的数,然后把某些位改成 6。
打了个表发现对于全 3 的数,模 66 的余数只有 3 和 33 两种情况,于是根据样例:
- 若余数为 33,考虑再加 33,即将后两位改成 6 即可;
- 若余数为 3,考虑再加 3033 即可。
若无法加则无解。
//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
//=============================================================
//=============================================================
//=============================================================
int main() {
//freopen("1.txt", "r", stdin);
std::ios::sync_with_stdio(0), std::cin.tie(0);
int T; std::cin >> T;
while (T --) {
int n; std::cin >> n;
std::string ans;
LL sum = 0;
for (int i = 1; i <= n; ++ i) ans.push_back('3'), sum = (10 * sum + 3) % 66;
if (sum == 33) {
ans[n - 1] = '6', ans[n - 2] = '6';
} else {
if (n == 1 || n == 3) ans = "-1";
else ans[n - 1] = '6', ans[n - 2] = '6', ans[n - 4] = '6';
}
std::cout << ans << "\n";
}
return 0;
}
C 构造
妈的不会构造被鲨了。
首先通过样例猜测,当 \(n\) 为奇数时 \(k=n\);\(n\) 为偶数时 \(k = 2^{\left\lfloor\log_2 n\right\rfloor + 1} - 1\),即两种情况都能取到上界。
//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 2e5 + 10;
//=============================================================
int n, ans[kN];
LL k;
//=============================================================
void check() {
int temp = 0;
for (int i = 1; i <= n; ++ i) {
if (i % 2 == 0) temp |= ans[i];
else temp &= ans[i];
}
std::cout << "---" << temp << "\n";
}
//=============================================================
int main() {
// freopen("1.txt", "r", stdin);
std::ios::sync_with_stdio(0), std::cin.tie(0);
int T; std::cin >> T;
while (T --) {
std::cin >> n;
if (n & 1) {
k = n;
ans[n] = n;
ans[n - 1] = n - 1;
ans[n - 2] = 1;
for (int i = 1; i <= n - 3; ++ i) ans[i] = i + 1;
} else {
k = (1ll << (((LL) log2(n)) + 1)) - 1l;
std::map<int, bool> vis;
std::vector<int> b[2];
int len = n;
ans[n] = n;
ans[n - 1] = k ^ n;
if ((k ^ n) == 1) {
len = 2;
} else {
len = 4;
ans[n - 2] = ans[n - 1] - 1;
ans[n - 3] = 1;
}
for (int i = n - len + 1; i <= n; ++ i) vis[ans[i]] = 1;
for (int i = 1; i <= n; ++ i) if (!vis[i]) b[i % 2].push_back(i);
for (int i = 1, j = 0; i <= n - len; ++ i, j ^= 1) ans[i] = b[j].back(), b[j].pop_back();
}
// check();
std::cout << k << "\n";
for (int i = 1; i <= n; ++ i) std::cout << ans[i] << " ";
std::cout << "\n";
}
return 0;
}
D 贪心,单调栈
先把每个数 2 的因子的次数 \(\operatorname{cnt}_i\) 求出来,记 \(a_i\) 除掉所有 2 的因子后剩下的部分为 \(b_i\)。
发现前缀 \(1\sim i\) 的最优操作方案,一定是将前缀 \(1\sim i - 1\) 的操作方案中,某些位置的 2 的因子全部贡献给 \(a_i\) 得到的。显然只要 \(b_j\le a_i = 2^{\operatorname{cnt}_i}\times b_i\) 就应当产生贡献,又发现一个位置只能向其他位置贡献一次,于是考虑单调栈维护当前有哪些位置能向之后产生贡献,每次加入一个数 \(a_i\) 时不断弹栈将贡献给到 \(a_i\) 即可。
注意上述判断条件 \(b_j\le 2^{\operatorname{cnt}_i}\times b_i\) 中,当 \(a_i\) 获得了若干 2 的幂后会变得很大,因此需要单独写个比较函数,特判 \(\operatorname{cnt}_i\) 较大时直接返回结果即可。
还需要写个快速幂,总时间复杂度 \(O(n\log v)\) 级别。
//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 2e5 + 10;
const LL p = 1e9 + 7;
//=============================================================
int n;
LL cnt2[kN], a[kN], b[kN], pw2[kN];
int top, st[kN];
//=============================================================
LL qpow(LL x_, LL y_) {
LL ret = 1;
while (y_) {
if (y_ & 1) ret = ret * x_ % p;
x_ = x_ * x_ % p, y_ >>= 1ll;
}
return ret;
}
bool cmp(int p1_, int p2_) {
if (pw2[p2_] > 30) return 1;
return (1ll << pw2[p2_]) * b[p2_] >= b[p1_];
}
//=============================================================
int main() {
// freopen("1.txt", "r", stdin);
std::ios::sync_with_stdio(0), std::cin.tie(0);
int T; std::cin >> T;
while (T --) {
std::cin >> n;
for (int i = 1; i <= n; ++ i) cnt2[i] = 0;
for (int i = 1; i <= n; ++ i) std::cin >> a[i], b[i] = a[i];
for (int i = 1; i <= n; ++ i) {
while (b[i] % 2 == 0) ++ cnt2[i], b[i] /= 2;
}
top = 0;
LL ans = 0;
for (int i = 1; i <= n; ++ i) {
ans += b[i];
pw2[i] = cnt2[i];
while (top && cmp(st[top], i)) {
pw2[i] += pw2[st[top]];
ans -= b[st[top]] * (qpow(2, pw2[st[top]]) - 1 + p) % p;
ans = (ans + p) % p;
pw2[st[top]] = 0;
-- top;
}
st[++ top] = i;
ans += b[i] * (qpow(2, pw2[i]) - 1 + p) % p;
ans %= p;
std::cout << ans << " ";
}
std::cout << "\n";
}
return 0;
}
E 结论,数论分块
//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const LL kInf = 1e18 + 2077;
//=============================================================
LL x, y, z, k, ans;
//=============================================================
void check(LL r_, LL c1_, LL d1_) {
LL c2 = kInf;
for (LL r = r_ * k + k, l; r > r_ * k; r = l - 1) {
l = std::max(r_ * k + 1, (LL) ceil(1.0 * (z - d1_) / ceil(1.0 * (z - d1_) / r)));
c2 = std::min(c2, x * (l - r_ * k) + y * ((LL) ceil(1.0 * (z - d1_) / l)));
}
ans = std::min(ans, c1_ + c2);
}
//=============================================================
int main() {
// freopen("1.txt", "r", stdin);
std::ios::sync_with_stdio(0), std::cin.tie(0);
int T; std::cin >> T;
while (T --) {
std::cin >> x >> y >> z >> k;
ans = kInf;
for (LL round = 0; ; ++ round) {
LL c1 = round * (k * x + y);
LL d1 = round * (round + 1ll) / 2ll * k;
if (d1 >= z) {
ans = std::min(ans, c1);
break;
}
check(round, c1, d1);
}
std::cout << ans << "\n";
}
return 0;
}
写在最后
怎么一堆思维结论题+打表,把我这种没脑子的呆瓜鲨了。
好想死掉。