Codeforces Round 1027 (Div. 3)


A. Square Year

题意:判断一个数是不是平方数。

点击查看代码
void solve() {
    std::string s;
    std::cin >> s;
    int n = 0;
    for (auto & c : s) {
    	n = n * 10 + c - '0';
    }

	int k = std::sqrt(n);
	while (k * k < n) {
		++ k;
	}

	if (k * k == n) {
		std::cout << 0 << " " << k << "\n";
	} else {
		std::cout << -1 << "\n";
	}
    
}


B. Not Quite a Palindromic String

题意:给你一个\(01\)串,长度为偶数。把它重新排列能不能使得\(s_i = s_{n-i+1}\)的位置个数恰好为\(k\)

首先需要拿\(\frac{n}{2}-k\)\(0, 1\)来匹配为不相等的位置,那么\(cnt_0, cnt_1\)都要大于等于\(\frac{n}{2}-k\)。然后看剩下的相同的两两配对能不能凑\(k\)个。

点击查看代码
void solve() {
    int n, k;
    std::cin >> n >> k;
    int cnt[2]{};
    std::string s;
    std::cin >> s;
    for (auto & c : s) {
    	++ cnt[c - '0'];
    }

    cnt[0] -= n / 2 - k;
    cnt[1] -= n / 2 - k;
    if (cnt[0] < 0 || cnt[1] < 0 || cnt[0] / 2 + cnt[1] / 2 < k) {
    	std::cout << "NO\n";
    } else {
    	std::cout << "YES\n";
    }
}

C. Need More Arrays

题意:一个排好序的数组,求一个最长的子序列,使得\(a_i > a_{i-1} + 1\)

从左到右模拟就行,优先选最小的数,这样让后面的数选择范围更大。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<int> a(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    }

    int ans = 1;
    for (int i = 1, last = a[0]; i < n; ++ i) {
    	if (last + 1 < a[i]) {
    		last = a[i];
    		++ ans;
    	}
    }
    std::cout << ans << "\n";
}


D. Come a Little Closer

题意:给你\(n\)个坐标,移动一个坐标,使得包含这些点的最小矩形的面积最小。

如果不移动,那么就是求最大最小的横纵坐标。
用两个\(multiset\)分别存\(x, y\)坐标,然后枚举删点。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<i64> x(n), y(n);
    std::multiset<i64> X, Y;
    for (int i = 0; i < n; ++ i) {
    	std::cin >> x[i] >> y[i];
    	X.insert(x[i]);
    	Y.insert(y[i]);
    }

    if (n == 1) {
    	std::cout << 1 << "\n";
    	return;
    }

    i64 ans = (*X.rbegin() - *X.begin() + 1) * (*Y.rbegin() - *Y.begin() + 1);
    for (int i = 0; i < n; ++ i) {
    	X.extract(x[i]);
    	Y.extract(y[i]);
    	i64 a = *X.rbegin() - *X.begin() + 1, b = *Y.rbegin() - *Y.begin() + 1;
    	i64 sum = a * b;
    	if (sum < n) {
    		ans = std::min({ans, sum + a, sum + b});
    	} else {
    		ans = std::min(ans, sum);
    	}

    	X.insert(x[i]);
    	Y.insert(y[i]);
    }

    std::cout << ans << "\n";
}

E. Kirei Attacks the Estate

题意:一棵树,每个点有点权,根为\(1\)。每个点可以向上延伸,一开始加\(a_u\),然后减\(a_{fa_u}\),然后加\(a_{fa_{fa_u}}\),也就是加减交替,终点任意。求每个点可以得到的最大值。

\(f[u], g[u]\)分别为起点为\(u\)的路径的最大最小值。那么一条路径起点为\(u\),现在起点变为它的子节点\(v\),那么路径上的点权的加减就变换了,也就是这条路径的和乘\(-1\)。这样就能得到\(f[v], g[v]\)

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<i64> a(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    }

    std::vector<std::vector<int>> adj(n);
    for (int i = 1; i < n; ++ i) {
    	int u, v;
    	std::cin >> u >> v;
    	-- u, -- v;
    	adj[u].push_back(v);
    	adj[v].push_back(u);
    }

    const i64 inf = 1e18;
    std::vector<i64> f(n), g(n);
    auto dfs = [&](auto & self, int u, int fa) -> void {
    	f[u] += a[u];
    	g[u] += a[u];
    	for (auto & v : adj[u]) {
    		if (v == fa) {
    			continue;
    		}

    		f[v] = std::max({0ll, -f[u], -g[u]});
    		g[v] = std::min({-f[u], -g[u]});
    		self(self, v,  u);
    	}
    };

    dfs(dfs, 0, -1);
    for (int i = 0; i < n; ++ i) {
    	std::cout << std::max(f[i], g[i]) << " \n"[i == n - 1];
    }
}

F. Small Operations

题意:两个数\(x, y\)\(x\)每次可以乘\([1, k]\)里的一个数,或者在\([1, k]\)里选一个\(x\)的因子把它除掉。求\(x\)变成\(y\)的最小操作数。

从质因子分解来看,其实就是\(x\)\(y\)多了一些质因子,也少了一些质因子,需要先把多的除掉,然后把少的乘起来。这两部分都可以\(dp\)。直接预处理每个数的因子,然后假设现在要凑出\(n\)来,那么对于\(n\)的每个因子之间转移就行,因为范围只有\(1e6\),因子最多的数只有两百多个。

点击查看代码
std::vector<std::vector<int>> g;

void init(int n) {
	g.assign(n + 1, {});
	for (int i = 1; i <= n; ++ i) {
		for (int j = i; j <= n; j += i) {
			g[j].push_back(i);
		}
	}
}

void solve() {
    int x, y, k;
    std::cin >> x >> y >> k;

    if (k == 1) {
    	std::cout << (x == y ? 0 : -1) << "\n";
    	return;
    }

    int d = std::gcd(x, y);
    x /= d, y /= d;

    const int inf = 1e9;
    auto work = [&](int n) -> int {
    	int m = g[n].size();
    	std::vector<int> f(m, inf);
    	f[0] = 0;
    	for (int i = 0; i < m; ++ i) {
    		if (f[i] == inf) {
    			continue;
    		}
    		for (int j = i + 1; j < m; ++ j) {
    			if (g[n][j] % g[n][i] == 0 && g[n][j] / g[n][i] <= k) {
    				f[j] = std::min(f[j], f[i] + 1);
    			} else if (g[n][j] / g[n][i] > k) {
    				break;
    			}
    		}
    	}

    	return f[m - 1] == inf ? -1 : f[m - 1];
    };

    int ans1 = work(x), ans2 = work(y);
    if (ans1 == -1 || ans2 == -1) {
    	std::cout << -1 << "\n";
    } else {
    	std::cout << ans1 + ans2 << "\n";
    }
}

G. Build an Array

待补

posted @ 2025-05-27 01:37  maburb  阅读(1073)  评论(0)    收藏  举报