Codeforces Round 927 (Div. 3) EFG

E:Link
题意:给定长度小于 \(4 \times 10^5\) 的整数 \(n\),求从 \(0\)\(n\) 各数位变化次数之和。
如:\(n = 12345\)
个位变化 \(12345\) 次,十位变化 \(1234\) 次,百位变化 \(123\) 次,以此类推。
考虑如何快速计算。
1 2 3 4 5
0 1 2 3 4
0 0 1 2 3
0 0 0 1 2
0 0 0 0 1

按列来算,可将复杂度降为 \(O(length)\)

void solve() {
	int n; cin >> n;
	string s; cin >> s;
	
	vector<int> a;
	int t = 0;
	for(auto &c : s) {
		t += c - '0';
		a.pb(t);
	}
	vector<int> ans;
	reverse(All(a));
	rep(i, 0, n - 2) {
		a[i + 1] += a[i] / 10;
		ans.pb(a[i] % 10);
	}
	t = a.back();
	while(t) {
		ans.pb(t % 10);
		t /= 10;
	}
	reverse(All(ans));
	int f = 0;
	for(int &x : ans) {
		if(x != 0) f = 1;
		if(f) cout << x;
	}
	cout << '\n';
}

F:Link
简单的数据结构优化 dp。
题意:\(m\) 条线段,选若干点,选一个点的同时会选中所有覆盖他的全部线段,每条线段只能被选一次,最大化被选线段数量。

  • \(dp[i]\) 表示 \([1, i]\) 中的答案。
  • \(cnt[i]\) 表示覆盖 \(i\) 的线段数量。
  • \(L[i]\) 表示所有覆盖 \(i\) 的线段左端点最小值。

那么

\[dp[i] = dp[j] + cnt[i] \ \ \ \ \ (j < L[i]) \]

\(L[i]\) 等价于右端点为 \([i, n]\) 的线段左端点最小值,从后往前扫一遍即可。

可以用树状数组实现。

void solve() {
	cin >> n >> m;
	a.init(n);
	vector<vector<int>> qr(n + 1); 
	rep(i, 1, m) {
		int l, r; cin >> l >> r;
		qr[r].pb(l);
		a.add(l, 1), a.add(r + 1, -1);
	}
	int minL = n + 1;
	per(i, n, 1) {
		for(int l : qr[i]) {
			minL = min(minL, l);
		}
		L[i] = min(i + 1, minL);
	}
	dp.init(n);
	rep(i, 1, n) {
		if(L[i] <= i) {
			dp.mod(i, dp.max(L[i] - 1) + a.sum(i));
		}
	}
	cout << dp.max(n) << '\n';
}

树状数组代码。

struct Fenwick_Tree {
	int t[N], n;
	int lowbit(int x) {
		return x & -x;
	}
	void init(int x, int v = 0) {
		n = x;
		rep(i, 1, n) t[i] = v;
	}
	void mod(int p, int v) {
		while(p <= n) {
			t[p] = std::max(t[p], v);
			p += lowbit(p);
		}
	}
	int max(int p) {
		int ret = 0;
		while(p) {
			ret = std::max(ret, t[p]);
			p -= lowbit(p);
		}
		return ret;
	}
	void add(int p, int v) {
		while(p <= n) {
			t[p] += v;
			p += lowbit(p);
		}
	}
	int sum(int p) {
		int ret = 0;
		while(p) {
			ret += t[p];
			p -= lowbit(p);
		}
		return ret;
	}
} a, dp;

G:拓欧求边权,跑 dij

posted @ 2024-02-19 02:42  Lu_xZ  阅读(6)  评论(0编辑  收藏  举报