Codeforces Round #701 (Div. 2)
A - Add and Divide
题意
有两个数a和b,每次可以选择把a除去b(下取整)或者把b加1,问最少操作几次使a等于0。
题解
显然这个操作次数不会很多,因为哪怕a是,b是2,最多操作32次肯定够了。
而且注意到第二个操作肯定放在操作的最前面。
于是暴力枚举第二个操作执行几次()即可。

#include <bits/stdc++.h> #define int long long #define Mid ((l + r) >> 1) #define lson (rt << 1) #define rson (rt << 1 | 1) using namespace std; int read(){ char c; int num, f = 1; while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0'; while(c = getchar(), isdigit(c)) num = num * 10 + c - '0'; return f * num; } int ans = 0, a, b; void work() { ans = 0x3f3f3f3f; a = read(); b = read(); int t1, t2, cnt; for(int i = 0; i <= 100; i++) { if(b + i == 1) continue; cnt = 0; t1 = a; t2 = b + i; while(t1 != 0) { t1 /= t2; cnt++; } ans = min(ans, cnt + i); } printf("%lld\n", ans); } signed main() { int Case = read(); while(Case--) work(); return 0; }
B - Replace and Keep Sorted
题意
定义b与a相似当且仅当:
a,b为严格单调递增的等长正数序列,a,b中的每个元素都在中,a,b只有一个元素不同。
有q个询问,每次询问与a的一个子段相似的b有多少个。
题解
因为只需要改变一个数,我们判断一下每个数可以变化的范围(大于左边的数小于右边的数)就行了。
但是注意区间两端的数需要特判,因为左端点只要大于0,右端点只要小于k+1即可。

#include <bits/stdc++.h> #define int long long #define Mid ((l + r) >> 1) #define lson (rt << 1) #define rson (rt << 1 | 1) using namespace std; int read(){ char c; int num, f = 1; while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0'; while(c = getchar(), isdigit(c)) num = num * 10 + c - '0'; return f * num; } const int N = 2e5 + 1009; int n, q, k, a[N], b[N]; void work() { n = read(); q = read(); k = read(); for(int i = 1; i <= n; i++) a[i] = read(); a[0] = 0; a[n + 1] = k + 1; for(int i = 1; i <= n; i++) b[i] = a[i + 1] - 1 - (a[i - 1] + 1) + 1 - 1 + b[i - 1]; //for(int i = 1; i <= n; i++) // cout << b[i] - b[i - 1] << endl; for(int i = 1; i <= q; i++) { int l = read(), r = read(); //cout << b[r - 1] - b[l] << endl; if(l == r) printf("%lld\n", k - 1); else printf("%lld\n", b[r - 1] - b[l] + a[l + 1] - 1 - 1 + k - a[r - 1] - 1); } } signed main() { int Case = 1; while(Case--) work(); return 0; }
C - Floor and Mod
题意
定义一对数是漂亮的,有,求中有多少对是漂亮的。
题解
我们把式子化简下。
枚举这个b,假设枚举到i。
另,提出k可以得到
把b除过来得到,且
显然a只能是之间的一个数而且a能被i整除,这样的a有个。
暴力枚举这个i可以发现答案是对的,但是会超时,继续观察,发现i很大的时候,分子全是x。
分子相同的时候统计这个和可以用数论分块解决。
因为的i最多有个,时间是的。
而大于的情况用数论分块之后也是的,所以总时间就是。

#include <bits/stdc++.h>
#define int long long
#define Mid ((l + r) >> 1)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
using namespace std;
int read(){
char c; int num, f = 1;
while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0';
while(c = getchar(), isdigit(c)) num = num * 10 + c - '0';
return f * num;
}
int x, y, ans;
void work() {
int l, r, i; ans = 0;
x = read(); y = read();
for(i = 1; i * i + i - 1 <= x && i <= y; i++) {
int r = i * i + i - 1;
ans += r / (i + 1);
}
//cout << i << endl;
l = i + 1;
for( ; l <= y + 1 && l <= x; l = r + 1) {
r = x / (x / l);
if(r > y + 1) break;
ans += x / l * (r - l + 1);
}
if(l <= x) {
r = y + 1;
ans += x / l * (r - l + 1);
}
printf(</span><span style="color: #800000;">"</span><span style="color: #800000;">%lld\n</span><span style="color: #800000;">"</span><span style="color: #000000;">, ans);
}
signed main()
{
int Case = read();
while(Case--) work();
return 0;
}
D - Multiples and Power Differences
题意
有一个的矩阵要求构造一个矩阵使得中的每个元素都是中对应元素的倍数,并且矩阵每个元素与上下左右四个元素之间的差的绝对值可以开四次方根。
中元素
题解
(谁能想到C题这么难的数学题之后搞道简单构造题出来)
1到16的最小公倍数是,是小于的,于是每个位置都可以填,但是相邻两个数要不一样怎么办。
那就的位置填,下一个位置是就减去就行了。
(还是要吐槽一句居然比C简单不少)

#include <bits/stdc++.h> #define Mid ((l + r) >> 1) #define lson (rt << 1) #define rson (rt << 1 | 1) using namespace std; int read(){ char c; int num, f = 1; while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0'; while(c = getchar(), isdigit(c)) num = num * 10 + c - '0'; return f * num; } int n, m, a[509][509]; signed main() { n = read(); m = read(); for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) a[i][j] = read(); for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { if((i + j - 1) & 1) printf("720720 "); else printf("%d ", 720720 - a[i][j] * a[i][j] * a[i][j] * a[i][j]); } printf("\n"); } return 0; }
E - Move and Swap
题意
有一棵树,根到所有叶子距离相等。
一开始红和蓝都在1号点,每次红可以选择一个儿子移动下去,蓝可以任意移动到下一层的一个节点。
然后你可以选择交换或者不交换红和蓝的位置。
然后对答案产生的贡献。
问把红和蓝最终移动到叶子上是总贡献最大是多少。
题解
树形dp。
表示红点走到x时的最大贡献。
单独考虑红点的转移:
红点可以来自他的父亲,这时候蓝点只要选择当前层的最大或者最小值就行了。
或者红点向下走一格后和蓝点交换,这个意思相当于蓝点选择一个儿子走下去,红点任意走。
转移到。
前一个转移是的,后面能不能也改成?
答案是肯定的。
把绝对值拆开
这样子
对于当前层的每一个y,统计一个的最大值和的最大值即可。

#include <bits/stdc++.h> #define int long long #define Mid ((l + r) >> 1) #define lson (rt << 1) #define rson (rt << 1 | 1) using namespace std; int read(){ char c; int num, f = 1; while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0'; while(c = getchar(), isdigit(c)) num = num * 10 + c - '0'; return f * num; } const int N = 2e5 + 1009; vector<int> son[N], nd[N]; int a[N], n, dth[N], maxx[N], minx[N], maxd, ans, maxa, maxb, f[N], fa[N]; void dfs(int x, int pre) { dth[x] = dth[pre] + 1; maxd = max(maxd, dth[x]); maxx[dth[x]] = max(maxx[dth[x]], a[x]); minx[dth[x]] = min(minx[dth[x]], a[x]); nd[dth[x]].push_back(x); for(auto j : son[x]) dfs(j, x); } void work() { n = read(); maxd = ans = 0; maxa = maxb = -1ll << 61; for(int i = 1; i <= n; i++) son[i].clear(), fa[i] = 0; for(int i = 2; i <= n; i++) { int x = read(); son[x].push_back(i); fa[i] = x; } for(int i = 2; i <= n; i++) a[i] = read(); for(int i = 1; i <= n; i++) nd[i].clear(); for(int i = 1; i <= n; i++) dth[i] = 0, maxx[i] = 0, minx[i] = 1ll << 61, f[i] = 0; dfs(1, 1); for(auto x : nd[2]) maxa = max(maxa, a[x]), maxb = max(maxb, -a[x]); for(int i = 2; i <= maxd; i++) { maxa = -1ll << 61; maxb = -1ll << 61; for(auto x : nd[i]) { maxa = max(maxa, f[fa[x]] + a[x]); maxb = max(maxb, f[fa[x]] - a[x]); } for(auto x : nd[i]) { //从他的父亲直接走下来 f[x] = max(f[x], f[fa[x]] + max(a[x] - minx[dth[x]], maxx[dth[x]] - a[x])); //从上一个地方换下来 f[x] = max(f[x], max(maxa - a[x], maxb + a[x])); ans = max(ans, f[x]); } } printf("%lld\n", ans); } signed main() { int Case = read(); while(Case--) work(); return 0; }
F - Copy or Prefix Sum
题意
有一列数b,要求构造数列a,使得每个,要么,要么,求构造方案数。
题解
看起来就像dp,往dp方面想。
可以构造是前i个数,前缀和为j的方案数。
假如满足第一种构造:,其中
假如满足第二种构造:,其中
两种相等当且仅当即第一种中的j=0。
要减去这个防止重复计算。
但这样时间复杂度是的,可以采取方法降低复杂度。
对于第一种操作,可以发现是所有元素像右移动个单位,可以用一个变量保存移动多少单位,可以解决。
对于第二种操作,是加上了所有元素的和,但当时重复计算,而在第一种操作的时候只是让位置变成了,所以直接让第二个位置等于所有元素的和就行了。
然后统计全局和。
发现除了位置变成上一个全局和外都没变,所以全局和改变了,变成。
这个可能很大,所以要用map当数组。

#include <bits/stdc++.h> #define int long long #define Mid ((l + r) >> 1) #define lson (rt << 1) #define rson (rt << 1 | 1) using namespace std; const int mod = 1e9 + 7; int read(){ char c; int num, f = 1; while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0'; while(c = getchar(), isdigit(c)) num = num * 10 + c - '0'; return f * num; }void work() {
int sum = 0, n;
map<int, int>f;
n = read();
int k = 0, ans = 1; f[0] = 1;
for(int qwq = 1; qwq <= n; qwq++) {
int x = read(), t;
t = f[k]; f[k] = ans; k -= x;
ans = (2 * ans - t + mod) % mod;
}
printf("%lld\n", ans);
}
signed main()
{
int Case = read();
while(Case--) work();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
2019-02-13 [Codeforces]Codeforces Round #538 (Div. 2)