Codeforces Round 959 sponsored by NEAR (Div. 1 + Div. 2)
题目链接:Codeforces Round 959 sponsored by NEAR (Div. 1 + Div. 2)
总结:Bwa两发,C读假题。发挥很一般,补题感觉到E都是能做的,红温。
A. Diverse Game
fag:签到
B. Fun Game
fag:位运算 + 思维
Description:给定一个两个
Solution:1与(0, 1)异或会将其改变, 0与任何数异或为0
- 那么假设
串中第一个不同的位置前面有 ,那么后面的数都可以与这个数异或,从而变得相等。如果没有但是 是
,则可以自己变为 ,或者不行。 - 即看
串中谁先出现 ,因为后面的数可以依靠的数改变。
Competing:有点慌乱,乱交了两发。难绷
void solve() { int n; cin >> n; string s, t; cin >> s >> t; for (int i = 0; i < n; i++) { if (s[i] == '1') { cout << "Yes\n"; return; } if (t[i] == '1') { cout << "No\n"; return; } } cout << "Yes\n"; }
C. Hungry Games
fag: 前缀和 + 二分
Description:给定
Solution:一般求区间个数,我会考虑前缀和或者双指针,因为所求区间个数往往很大。
- 我们简单模拟下,开始
不断增大,然后变为 ,然后再增大。那么对于变为 之后再增大这部分是不是等价于以这个位置为起点,进行相同的操作。显然我们暴力求解会计算很多相同的状态,考虑优化。 - 我们用
表示以这个点为起点的方案数。那么 ,其中 是变为 的位置。 - 我们需要用后面的位置更新前面的位置,所以我们从后面开始计算。那么怎么计算
的位置呢?因为 是递增的,考虑二分。
void solve(){ int n, x; cin >> n >> x; vector<int> a(n + 5, 1e18), s(n + 5, 1e18); s[0] = 0; for (int i = 1; i <= n; i ++){ cin >> a[i]; s[i] = s[i - 1] + a[i]; // 前缀和 } vector<int> cnt(n + 5); LL ans = 0; for (int i = n; i; i --){ // 我们从后往前计算答案,cnt[i]表示以i为起点有多少符合条件的子串 // 我们从i点开始找到第一个不符合条件的点(第一个子串的结尾) int idx = lower_bound(s.begin(), s.end(), s[i - 1] + x + 1) - s.begin(); // 但是它在idx处清0了,因此从idx + 1起又开始从新计算答案(但是我们已经记录下来了) cnt[i] += cnt[idx + 1] + (idx - i); ans += cnt[i]; } cout << ans << endl; }
D. Funny Game
fag:并查集 + 鸽巢原理
Solution:给定
Description:样例全是
- 考虑每次如何保证每次取的数是两个不同的连通块,使用并查集维护信息,每次只取代表节点即可(
)。
int f[N]; void init(){ for (int i = 0; i < N; i ++) f[i] = i; } int find(int x){ if (x != f[x]) f[x] = find(f[x]); return f[x]; } bool merge(int x, int y){ int fx = find(x), fy = find(y); if (fx == fy) return false; f[fx] = fy; return true; } void solve(){ cin >> n; vector<int> a(n + 1); for (int i = 1; i <= n; i ++){ cin >> a[i]; } vector<pii> ans(n); for (int i = n - 1; i; i --){ vector<int> p(n, -1); for (int j = 1; j <= n; j ++){ if (find(j) == j){ int r = a[j] % i; if (p[r] != -1){ merge(p[r], j); ans[i] = {p[r], j}; break; } else p[r] = j; } } } cout << "Yes\n"; for (int i = 1; i < n; i ++){ cout << ans[i].fi << " " << ans[i].se << endl; } }
E. Wooden Game
fag:贪心 + 二进制
Description:有
Solution:题目求按位或的最大值,我们显然要想到位运算。
-
对于每一棵树,如果他的大小为
,那么我们可以取 的任意一个值出来运算,只需要删去一定数量的叶子节点。 -
等价于每个数的可以为
,求它们异或的最大值。 -
我们从最高位开始一位一位看,如果该位有两个数都是
,那么该位可以取 ,后面的所有位都可以取 。将其中一个数减 即可。 -
该位只有一个数为
,那么该位取 。
void solve(){ cin >> n; vector<int> a(n); vector<int> cnt(32); for (int i = 0; i < n; i ++){ cin >> a[i]; for (int j = 0; j < a[i] - 1; j ++){ int x; cin >> x; } for (int j = 31; ~j; j --){ if ((a[i] >> j) & 1) cnt[j] ++; } } int ans = 0; for (int i = 31; ~i; i --){ if (cnt[i] >= 2){ ans |= (1LL << (i + 1)) - 1; break; } else if (cnt[i]){ ans |= 1LL << i; } } cout << ans << endl; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!