2026.6.27 Codeforces Round 1105 (Div. 2)
A. Another Popcount Problem
题意
给定 \(n, k\),构造一个长度为 \(k\) 序列,和为 \(n\),二进制位数和最大。
题解
贪心,从低位到高位构造。
void solve()
{
ll n, m; cin >> m >> n;
if (m <= n) cout << m << '\n';
else
{
ll ans = 0;
for (int k=0; k<31; ++k)
{
if (m >= (n<<k)) m -= n<<k, ans += n;
else
{
ans += m>>k; break;
}
}
cout << ans << '\n';
}
}
B. AI Finds Nothing Here
题意
称 \(n\times m\) 的 01 矩阵为好矩阵如果它的所有 \(r\times c\) 子矩阵异或和都为 \(0\)。给定 \(n,m,r,c\) 求好矩阵数量,对 \(998244353\) 取模。
题解
只要确定左上角的 \(r-1\) 行和 \(c-1\) 列就能递推确定剩下的元素。所以答案是 \(2^{nm - (n-r+1)(m-c+1)}\)。
void solve()
{
int n, m, r, c; cin >> n >> m >> r >> c;
cout << qpow(2, 1ll * n * m - 1ll * (n-r+1) * (m-c+1)) << '\n';
}
C. Nim Game Is XOR Game
题意
\(n\) 堆石子,两人博弈,每个人可以取走数量异或和为 \(0\) 的石子(不能不取),无法操作者输,求先手必胜方案数。
题解
没有石子或只有一堆非空石子是必败的;
在其他任何情况下,都可以取空 \(n-1\) 堆石子再从最后一堆石子中取一部分来达到上面的必败态。
void solve()
{
int n; cin >> n;
vector <int> a(n);
int s = 0;
for (int i=0; i<n; ++i) cin >> a[i], s ^= a[i];
if (n == 1) { cout << "0\n"; return; }
if (!s) { cout << "1\n"; return; }
int ans = 0;
for (int i=0; i<n; ++i)
{
if (a[i] > (s^a[i])) ++ans;
}
cout << ans << '\n';
}
D. Decidophobia
题意
\(n\) 个人围成一圈,每个人有一个权值 \(a_i\)。现要给其中一些人发礼物,分发后,每个人有一个分数:
若他收到了礼物,则分数为左右 \(2d\) 个人中没有礼物的人数乘 \(a_i\);若他没收到礼物,则分数为左右 \(2d\) 个人中有礼物的人数乘 \(-a_i\)。
求所有人分数之和的最大值。
题解
先假设所有人都没发礼物,则给一个人礼物对总分的贡献是 \(2d\times a_i\) 减去周围 \(2d\) 个人的权值。
void solve()
{
int n, d; cin >> n >> d;
vector <ll> a(n*3+1), s(n*3+1);
for (int i=1; i<=n; ++i) cin >> a[i], a[i+n] = a[i+2*n] = a[i];
for (int i=1; i<=n*3; ++i) s[i] = s[i-1] + a[i];
ll ans = 0;
for (int i=1; i<=n; ++i)
{
ll w = a[i] * d * 2 - (s[i+n+d] - s[i+n]) - (s[i+n-1] - s[i+n-d-1]);
ans += max(w, 0ll);
}
cout << ans << '\n';
}
E. Revival
题意
对一个排列 \(p\),定义 \(s_i\) 为 \(p\) 的第 \(i\) 个前缀的逆序对数。现对每个位置 \(i\) 给出 \(p_i\) 和 \(s_i\) 之一,还原排列 \(p\)。保证解一定存在。
题解
从后往前依次确定每个 \(s_i\) 对应的 \(p_i\)。
假设当前最后一个未确定的位置为 \(r\),倒数第二个未确定的位置为 \(l\)。我们已知 \(s_r, s_l\) 和当前未填入排列的数字集合 \(S\)。
则 \(s_r - s_l\) 就是 \(a_{l+1, \dots, r-1}\) 的贡献(可直接计算)和 \(a_r := x\) 的贡献。将未知项拆分出来就是
其中 \(V(x, S) = \sum_{y\in S} [y>x]\)。
用树状数组维护逆序对即可。\(x\) 可以直接二分。复杂度 \(O(n\log^2 n)\)(其实也可以 \(O(n\log n)\))
struct bit
{
int n;
vector <int> c;
bit(int n) : n(n) { c.resize(n+1); }
void upd(int x, int v=1)
{
for (; x; x-=x&-x) c[x] += v;
}
int qry(int x)
{
int r = 0;
for (; x<=n; x+=x&-x) r += c[x];
return r;
}
};
void solve()
{
int n; cin >> n;
vector <char> c(n+1);
vector <ll> a(n+1);
vector <int> ans(n+1);
for (int i=1; i<=n; ++i)
{
string _;
cin >> _ >> a[i];
c[i] = _[0];
}
bit p(n), q(n);
for (int i=1; i<=n; ++i) p.upd(i, 1), q.upd(i, 1);
int l, r = n;
while (c[r] == 'p')
{
p.upd(a[r], -1), q.upd(a[r], -1);
ans[r] = a[r];
--r;
}
while (r>0)
{
l = r-1;
while (l>0 && c[l] == 'p') --l;
ll val = a[r] - a[l] + (r-l-1);
for (int i=r-1; i>l; --i)
{
val -= p.qry(a[i]+1);
p.upd(a[i], -1);
q.upd(a[i], 1);
ans[i] = a[i];
}
int L = 1, R = n, mid, res;
while (L <= R)
{
mid = (L+R) >> 1;
if (q.qry(mid+1) <= val) res = mid, R = mid-1;
else L = mid+1;
}
p.upd(res, -1), q.upd(res, -1);
for (int i=r-1; i>l; --i) q.upd(a[i], -2);
ans[r] = res; r = l;
}
for (int i=1; i<=n; ++i) cout << ans[i] << ' ';
cout << '\n';
}

浙公网安备 33010602011771号