Codeforces Round 757 (Div. 2)

我不知道为什么要补这一个远古场,但是确实里面几道题有点意思。
C. Divan and bitwise operations
显然,我们可以得到整个序列的按位或就是所有 \(x\) 的按位或,设为 \(S\)。
如果 \(S\) 的第 \(i\) 位为 \(0\),贡献即为 \(0\)。
否则总有一个 \(1\),当中恰有一个对应贡献为 \(2^i\) ,总贡献为 \(2^i×2^{n−1}\)。
那么 \(Ans=S×2^{n−1}\)。
时间复杂度 \(O(Tn)\)。
D. Divan and Kostomuksha
D1和D2我就一起讲了,本质没区别。
要求重排序列,求下面一坨的最大值
设 \(sum_i\) 表示序列里有因子 \(i\) 的数的个数,\(dp_i\) 表示选的数全有因子 \(i\) 前缀gcd和的最大值。
考虑转移,因为公因子只会随着加入的数变多而变小,故倒序转移,先算下标大的dp值。
考虑枚举因子 \(j\),\(dp_i = \max(dp_{i*j} + i*(sum_i-sum_{i*j}))\)
如此暴力转移,是可以过D1的,但是D2会TLE。那么我们如何优化呢?
注意到每个数都可以分解冲若干个质数之积,所以每次转移时只需要考虑质数,而其他的已经在之前考虑过了。这样我们就可以用一种类似埃氏筛的东西算出所有dp值。
优化后状态转移的复杂度变成了 \(O(wloglogw)\) (其中\(w\)指值域大小)
const int Maxn = 2e7 + 1;
const int N = 1e5 + 5;
int n, a[N], sum[Maxn]; ll dp[Maxn];
bool vis[Maxn]; int q, k, prime[Maxn / 10], cnt = 0;
inline void sieve(void) {
Ms(prime, 0); Ms(vis, false); cnt = 0; vis[1] = true;
for (int i = 2; i < Maxn; i++) {
if (!vis[i]) { prime[++cnt] = i; }
for (int j = 1; prime[j] * i < Maxn && j <= cnt; j++) {
vis[prime[j] * i] = true;
if (i % prime[j] == 0) { break; }
}
}
}
signed main(void) {
sieve(); read(n);
for (int i = 1; i <= n; i++) {
read(a[i]); sum[a[i]]++;
if (a[i] != 1) sum[1]++;
for (int j = 2; j * j <= a[i]; j++) {
if (a[i] % j) continue;
sum[a[i] / j]++; sum[j]++;
if (j * j == a[i]) sum[j]--;
}
}
ll ans = 0;
for (int i = Maxn - 1; i >= 1; i--) {
dp[i] = 1ll * sum[i] * i;
for (int j = 1; prime[j] * i < Maxn && j <= cnt; j++)
chkmax(dp[i], dp[prime[j] * i] + 1ll * (sum[i] - sum[prime[j] * i]) * i);
if (sum[i] == n) chkmax(ans, dp[i]);
}
writeln(ans);
//fwrite(pf, 1, o1 - pf, stdout);
return 0;
}
E. Divan and a Cottage
考虑动态开点线段树维护温度值域。其中一个节点维护这个区间所有温度当前的最小值和最大值。
不妨设新的一天温度为 \(T\),如果区间最大值小于 \(T\),那么整个区间温度都要加 \(1\),反之亦然。当遇到区间最大值等于最小值时,温度应该也等于 \(T\),返回即可。注意到这本质上是在线段树上二分,复杂度一个 \(log\)。
那么给定初始温度后,只要进行单点查询即可,查询时注意懒标记的下传。
时间复杂度 \(O(nklogw)\) (其中\(w\)指值域大小)
const int N = 2e5 + 5;
const int mod = 1e9 + 1;
int n, k, T[N];
const int M = 3e7 + 5;
int mx[M], mn[M], ls[M], rs[M], tag[M], tot;
inline void addtag(int pos, int val) { mx[pos] += val; mn[pos] += val; tag[pos] += val; }
inline void pushdown(int pos, int l, int r) {
if (!tag[pos]) return;
if (ls[pos]) addtag(ls[pos], tag[pos]);
if (rs[pos]) addtag(rs[pos], tag[pos]);
tag[pos] = 0;
}
inline void pushup(int pos) {
mx[pos] = max(mx[ls[pos]], mx[rs[pos]]);
mn[pos] = min(mn[ls[pos]], mn[rs[pos]]);
}
inline int newnode(int l, int r) { ++tot; ls[tot] = rs[tot] = tag[tot] = 0; mx[tot] = r, mn[tot] = l; return tot; }
inline void update(int pos, int l, int r, int t) {
if (mx[pos] < t) return (void) addtag(pos, 1);
if (mn[pos] > t) return (void) addtag(pos, -1);
if (mx[pos] == mn[pos]) return;
int mid = l + r >> 1;
if (!ls[pos]) ls[pos] = newnode(l, mid);
if (!rs[pos]) rs[pos] = newnode(mid + 1, r);
pushdown(pos, l, r);
update(ls[pos], l, mid, t), update(rs[pos], mid + 1, r, t);
pushup(pos);
}
inline int query(int pos, int l, int r, int t) {
if (l == r) return mx[pos];
int mid = l + r >> 1;
if (!ls[pos]) ls[pos] = newnode(l, mid);
if (!rs[pos]) rs[pos] = newnode(mid + 1, r);
pushdown(pos, l, r);
if (t <= mid) return query(ls[pos], l, mid, t);
else return query(rs[pos], mid + 1, r, t);
}
signed main(void) {
read(n); int lstans = 0, rt = newnode(0, 1e9);
for (int i = 1; i <= n; i++) {
read(T[i]), read(k);
update(rt, 0, 1e9, T[i]);
while (k--) {
int x; read(x);
x = (x + lstans) % mod;
lstans = query(rt, 0, 1e9, x);
writeln(lstans);
}
}
//fwrite(pf, 1, o1 - pf, stdout);
return 0;
}

浙公网安备 33010602011771号