Codeforces Round 952 (Div. 4) (A - H2)

Codeforces Round 952 (Div. 4)

A#

void solve() {
	string s, t; cin >> s >> t;
	swap(s[0], t[0]);
	cout << s << ' ' << t << '\n';
}

B#

原数据范围枚举足矣。

进一步分析性质:x+2x+nxx=xnx(1+nx)2,对较大的 n 来说,答案取决于 nx 的大小,显然取 x=2 最优。

对于较小的 n,打标验证只有 3 是例外。

void solve() {
    int n;
    std::cin >> n;
    
    if (n == 3) {
        std::cout << 3 << "\n";
    } else {
        std::cout << 2 << "\n";
    }
}
// by jiangly

C#

设当前前缀和为 s,检查是否存在 x=sx

void solve() {
	int n; cin >> n;
	ll s = 0, ans = 0;
	map<ll, int> mp;
	for(int i = 1, x; i <= n; ++ i) {
		cin >> x;
		mp[x] = 1;
		s += x;
		if(s % 2 == 0) {
			ans += mp[s / 2];
		}
	}
	cout << ans << '\n';
	
}

D#

题目保证了是完整的圆。找到左右边界即可。

void solve() {
	int n, m; cin >> n >> m;
	int mx[2] = {1, 1}, mi[2] = {n, m};
	
	for(int i = 0; i < n; ++ i) {
		string s; cin >> s;
		for(int j = 0; j < m; ++ j) {
			if(s[j] == '#') {
				mx[0] = max(mx[0], i + 1);
				mi[0] = min(mi[0], i + 1);
				mx[1] = max(mx[1], j + 1);
				mi[1] = min(mi[1], j + 1);
			}
		}
	}
	cout << (mx[0] + mi[0]) / 2 << ' ' << (mx[1] + mi[1]) / 2 << '\n';
}

E#

枚举 k=a×b×c。可以 O(xy) 枚举 a,b,再检查 c

void solve() {
	ll x, y, z, k; cin >> x >> y >> z >> k;
	ll ans = 0;
	for(int a = 1; a <= x; ++ a) {
		for(int b = 1; b <= y; ++ b) {
			ll c = k / a / b;
			if(c * a * b != k || c > z) continue;
			ans = max(ans, (x - a + 1) * (y - b + 1) * (z - c + 1));
		}
	}
	cout << ans << '\n';
}

F#

二分时间 t。对于一种攻击,第一天是一定要的,剩下可以攻击 t1ci 次。

bool check(ll v) {
	__int128 s = 0;
	for(int i = 1; i <= n; ++ i) {
		s += a[i] * __int128((v - 1) / c[i] + 1);
	}
	return s >= h;
}

void solve() {
	cin >> h >> n;
	for(int i = 1; i <= n; ++ i) cin >> a[i];
	for(int i = 1; i <= n; ++ i) cin >> c[i];
	ll l = 1, r = 1e18;
	while(l < r) {
		ll mid = l + r >> 1;
		if(check(mid)) r = mid;
		else l = mid + 1;
	}
	cout << l << '\n';
}

G#

d(kn)=kd(n) 成立当且仅当 nk 后不进位,证明待补。

x=9k。对于一个长度为 i 的数字 n,最高位 [1,x],剩余位 [0,x],总个数为 (x1)xi1

符合条件的数字长度 [l+1,r]。则合法数字个数为 (x1)(xl++xr1)=xrxl

void solve() {
	cin >> l >> r >> k;
	if(k >= 10) {
		cout << 0 << '\n';
		return;
	}
	ll x = 9 / k + 1;
	ll ans = (qpow(x, r) - qpow(x, l)) % P;
	if(ans < 0) ans += P;
	cout << ans << '\n';
}

H1#

只考虑行,列同理处理。

定义行 i 的额外贡献 ri 为不属于 i,但把 i 涂黑后属于一个连通块的节点数量。

对于一个大小为 g 的连通块 G,会对所有贯穿 G 的行以及与 G 相邻的行产生额外贡献。

ri=gcntx(i)cntx(i) 表示属于 G 且横坐标为 i 的节点数量。

最后答案为 m+max(ri)

int dx[] = {1, -1, 0, 0}, dy[] = {0, 0, 1, -1};

void solve() {
	int n, m; cin >> n >> m;
	vector<string> g(n);
	for(int i = 0; i < n; ++ i) {
		cin >> g[i];
	}
	vector<int> r(n, 0);
	vector<int> c(m, 0);
	vector id(n, vector<int>(m, 0));
	
	auto ck = [&](int x, int y) {
		return x >= 0 && x < n && y >= 0 && y < m;
	};
	int idx = 0;
	vector<int> cnt_r(n, 0);
	vector<int> cnt_c(m, 0);
	vector<int> st_r(n, 0);
	vector<int> st_c(m, 0);
	
	for(int i = 0; i < n; ++ i) {
		for(int j = 0; j < m; ++ j) {
			if(!id[i][j] && g[i][j] == '#') {
				id[i][j] = ++ idx;
				queue<pair<int, int>> q;
				vector<pair<int, int>> a;
				q.eb(i, j);
				while(!q.empty()) {
					auto [x, y] = q.front(); q.pop();
					++ cnt_r[x];
					++ cnt_c[y];
					a.pb(x, y);
					for(int k = 0; k < 4; ++ k) {
						int nx = x + dx[k], ny = y + dy[k];
						if(ck(nx, ny) && !id[nx][ny] && g[nx][ny] == '#') {
							q.eb(nx, ny);
							id[nx][ny] = idx;
						}
					}
				}
				for(auto [x, y] : a) {
					if(!st_r[x]) {
						st_r[x] = 1;
						r[x] += a.size() - cnt_r[x];
					}
					if(!st_c[y]) {
						st_c[y] = 1;
						c[y] += a.size() - cnt_c[y];
					}
					for(int k = 0; k < 4; ++ k) {
						int nx = x + dx[k], ny = y + dy[k];
						if(ck(nx, ny)) {
							if(!st_r[nx]) {
								st_r[nx] = 1;
								r[nx] += a.size() - cnt_r[nx];
							}
							if(!st_c[ny]) {
								st_c[ny] = 1;
								c[ny] += a.size() - cnt_c[ny];
								
							}
						}
					}
				}
				for(auto [x, y] : a) {
					st_r[x] = st_c[y] = 0;
					-- cnt_r[x];
					-- cnt_c[y];
					for(int k = 0; k < 4; ++ k) {
						int nx = x + dx[k], ny = y + dy[k];
						if(ck(nx, ny)) {
							st_r[nx] = st_c[ny] = 0;
						}
					}
				}
			}
		}
	}
	int ans = max(n, m);
	for(int i = 0; i < n; ++ i) {
		ans = max(ans, m + r[i]);
	}
	for(int j = 0; j < m; ++ j) {
		ans = max(ans, n + c[j]);
	}
	cout << ans << '\n';
}

H2#

和 H1 思路一致。

G 对行 i 的额外贡献为 ri,列 j 的额外贡献为 cj

i,j 染色后的连通块大小是否为 n+m1+ri+cj

如果一个 G 同时对 i,j 产生了额外贡献,应当被记入答案的贡献为 gcntx(i)cnty(j)+cntxy(i,j),实际记入 (gcntx(i))+(gcnty(i))

重复计算了 gcntxy(i,j)

枚举 G 产生贡献的行 ij,把 gcntxy(i,j) 加入 rci,j 表示 i,j 重复计算的个数。

连通块大小是 g=O(nm) 的,而有贡献的 i×j=(连通块的行数 + 周围一圈)×(连通块的列数 + 周围一圈)=O(?),所以总复杂度 O(?)

upd:最坏复杂度 O(n3/6),可以恰好通过。

int dx[] = {1, -1, 0, 0}, dy[] = {0, 0, 1, -1};

void solve() {
	int n, m; cin >> n >> m;
	vector<string> g(n);
	for(int i = 0; i < n; ++ i) {
		cin >> g[i];
	}
	vector<int> r(n, 0);
	vector<int> c(m, 0);
	vector rc(n, vector<int>(m, 0));
	vector id(n, vector<int>(m, 0));
	
	auto ck = [&](int x, int y) {
		return x >= 0 && x < n && y >= 0 && y < m;
	};
	int idx = 0;
	vector<int> cnt_r(n, 0);
	vector<int> cnt_c(m, 0);
	vector cnt_rc(n, vector<int>(m, 0));
	vector<int> st_r(n, 0);
	vector<int> st_c(m, 0);
	
	for(int i = 0; i < n; ++ i) {
		for(int j = 0; j < m; ++ j) {
			if(!id[i][j] && g[i][j] == '#') {
				id[i][j] = ++ idx;
				queue<pair<int, int>> q;
				vector<pair<int, int>> a;
				q.eb(i, j);
				while(!q.empty()) {
					auto [x, y] = q.front(); q.pop();
					++ cnt_r[x];
					++ cnt_c[y];
					++ cnt_rc[x][y];
					a.pb(x, y);
					for(int k = 0; k < 4; ++ k) {
						int nx = x + dx[k], ny = y + dy[k];
						if(ck(nx, ny) && !id[nx][ny] && g[nx][ny] == '#') {
							q.eb(nx, ny);
							id[nx][ny] = idx;
						}
					}
				}
				vector<int> X, Y;
				for(auto [x, y] : a) {
					if(!st_r[x]) {
						st_r[x] = 1;
						r[x] += a.size() - cnt_r[x];
						X.pb(x);
					}
					if(!st_c[y]) {
						st_c[y] = 1;
						c[y] += a.size() - cnt_c[y];
						Y.pb(y);
					}
					for(int k = 0; k < 4; ++ k) {
						int nx = x + dx[k], ny = y + dy[k];
						if(ck(nx, ny)) {
							if(!st_r[nx]) {
								st_r[nx] = 1;
								r[nx] += a.size() - cnt_r[nx];
								X.pb(nx);
							}
							if(!st_c[ny]) {
								st_c[ny] = 1;
								c[ny] += a.size() - cnt_c[ny];
								Y.pb(ny);
								
							}
						}
					}
				}
				
				for(auto x : X) {
					for(auto y : Y) {
						if(ck(x, y)) {
							rc[x][y] += a.size() - cnt_rc[x][y];
						}
					}
				}
				for(auto [x, y] : a) {
					st_r[x] = st_c[y] = 0;
					-- cnt_r[x];
					-- cnt_c[y];
					-- cnt_rc[x][y];
					for(int k = 0; k < 4; ++ k) {
						int nx = x + dx[k], ny = y + dy[k];
						if(ck(nx, ny)) {
							st_r[nx] = st_c[ny] = 0;
						}
					}
				}
			}
		}
	}
	int ans = n + m - 1;
	for(int i = 0; i < n; ++ i) {
		for(int j = 0; j < m; ++ j) {
			int tmp = n + m - 1;
			ans = max(ans, tmp + r[i] + c[j] - rc[i][j]);
			
		}
	}
	cout << ans << '\n';
}
posted @   Lu_xZ  阅读(613)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示