Codeforces Round 757 (Div. 2)

我不知道为什么要补这一个远古场,但是确实里面几道题有点意思。


C. Divan and bitwise operations

显然,我们可以得到整个序列的按位或就是所有 x 的按位或,设为 S

如果 S 的第 i 位为 0,贡献即为 0

否则总有一个 1,当中恰有一个对应贡献为 2i ,总贡献为 2i×2n1

那么 Ans=S×2n1

时间复杂度 O(Tn)


D. Divan and Kostomuksha

D1和D2我就一起讲了,本质没区别。

要求重排序列,求下面一坨的最大值

i=1ngcd(a1,a2,,ai),

sumi 表示序列里有因子 i 的数的个数,dpi 表示选的数全有因子 i 前缀gcd和的最大值。

考虑转移,因为公因子只会随着加入的数变多而变小,故倒序转移,先算下标大的dp值。

考虑枚举因子 jdpi=max(dpij+i(sumisumij))

如此暴力转移,是可以过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;
}
posted @ 2025-03-05 01:38  EternalEpic  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示