VP Educational Codeforces Round 34 (Rated for Div. 2)


A. Hungry Student Problem

枚举

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    for (int i = 0; i <= n / 3; ++ i) {
    	if ((n - 3 * i) % 7 == 0) {
    		std::cout << "YES\n";
    		return;
    	}
    }

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

B. The Modcrab

模拟

点击查看代码
void solve() {
    int h1, a1, c1, h2, a2;
    std::cin >> h1 >> a1 >> c1 >> h2 >> a2;
    std::vector<std::string> ans;
    while(h2 > 0) {
    	if (h1 > a2 || h2 - a1 <= 0) {
    		ans.push_back("STRIKE");
    		h2 -= a1;
    	} else {
    		ans.push_back("HEAL");
    		h1 += c1;
    	}

    	h1 -= a2;
    }

    std::cout << ans.size() << "\n";
    for (auto & s : ans) {
    	std::cout << s << "\n";
    }
}

C. Boxes Packing

题意:给你\(n\)个数,每个数可以被比自己大的一个数消除,每个数只能消除一次。问最少留下几个数。

最优的方法应该是从小到大一个一个消除,那么发现会有多余的数无法消除,显然最大的数都无法消除,其它无法消除的数是因为比它大的数比它少。那么会剩下出现次数最多的数的个数的数。

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

    int ans = 0;
    for (auto & [x, y] : cnt) {
    	ans = std::max(ans, y);
    }

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

D. Almost Difference

题意:给你\(n\)个数,对于两个数\(a_i, a_j\),如果它们相差大于\(1\),那么值为\(a_j - a_i\)。求所有\(i < j\)\(i, j\)的值。

从前往后做,那么就变成了找\([1, a_j - 2]\)的数的出现次数以及总和,还有\([a_j + 2, V]\)的数的出现次数以及总和。其中\(V\)是最大的数的值。那么我们离散化后用两个树状数组分别维护这两个值就行了。记住对于\(a_i\),要把\(a_i - 1, a_i + 1\)也加入离散化,不然可能离散化后跟\(a_i\)相邻的数相差会大于\(1\)
还有一个就是这题要用\(int128\)

点击查看代码
template <class T>
struct Fenwick {
    int n;
    std::vector<T> tr;

    Fenwick(int _n) {
        init(_n);
    }

    void init(int _n) {
        n = _n;
        tr.assign(_n + 1, T{});
    }

    void add(int x, const T &v) {
        for (int i = x; i <= n; i += i & -i) {
            tr[i] = tr[i] + v;
        }
    }

    T query(int x) {
        T res{};
        for (int i = x; i; i -= i & -i) {
            res = res + tr[i];
        }
        return res;
    }

    T sum(int l, int r) {
        return query(r) - query(l - 1);
    }
};

std::ostream & operator << (std::ostream & out, i128 n) {
	bool flag = false;
	if (n < 0) {
		flag = true;
		n = -n;
	}

	std::vector<int> res;
	do {
		res.push_back(n % 10);
		n /= 10;
	} while (n != 0);

	std::reverse(res.begin(), res.end());
	if (flag) {
		out << "-";
	}
	
	for (auto & x : res) {
		out << x;
	}

	return out;
}

void solve() {
    int n;
    std::cin >> n;
    std::vector<i64> a(n), b;
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    	b.push_back(a[i]);
    	b.push_back(a[i] + 1);
    	b.push_back(a[i] - 1);
    }

    b.push_back(0);
    b.push_back(-1);
    b.push_back(-2);

    std::sort(b.begin(), b.end());
    b.erase(std::unique(b.begin(), b.end()), b.end());
    int m = b.size();
    auto get = [&](i64 x) -> int {
    	return std::lower_bound(b.begin(), b.end(), x) - b.begin();
    };

    Fenwick<i128> tr(m + 2), cnt(m + 2);
    i128 ans = 0;
    for (auto & x : a) {
    	int y = get(x);
    	ans += cnt.sum(1, y - 2) * x - tr.sum(1, y - 2) ;
    	ans += cnt.sum(y + 2, m + 2) * x - tr.sum(y + 2, m + 2);
    	tr.add(y, x);
    	cnt.add(y, 1);
    }

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

E. Swapping Characters

题意:给定\(n\)个长度相同的字符串。求有没有一个字符串,使得所有字符串都是被这个字符串交换其中字符恰好一次变化过来的。

如果有答案,那么\(s_1\)一定是交换一次变过来的,考虑逆操作,我们枚举交换\(s_1\)的两个位置,然后检查其它字符串能不能通过它恰好一次变化过来。这样每次检查的时间复杂度不能接受。可以预处理每个字符串和\(s1\)不同地方的个数,那么每次交换两个位置,只需要讨论这个位置的贡献就行了。判断能不能变化过来就是,不同的位置只能是\(0\)个或者\(2\)个,如果是\(0\)个,因为必须交换两个不同的位置,那么这个字符串必须要由两个相同的字符。如果是\(2\)个,那么找到这两个位置,判断交换后是不是相等就行了。

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

	std::vector<int> f(n);
	for (int i = 0; i < n; ++ i) {
		for (int j = 0; j < m; ++ j) {
			for (int k = j + 1; k < m; ++ k) {
				f[i] |= s[i][j] == s[i][k];
			}
		}
	}

	std::vector st(n, std::vector<int>(m));
	std::vector<int> cnt(n);
	for (int i = 1; i < n; ++ i) {
		for (int j = 0; j < m; ++ j) {
			st[i][j] += s[0][j] != s[i][j];
			cnt[i] += s[0][j] != s[i][j];
		}
	}

	for (int i = 0; i < m; ++ i) {
		for (int j = i + 1; j < m; ++ j) {
			for (int k = 1; k < n; ++ k) {
				st[k][i] -= s[0][i] != s[k][i];
				st[k][j] -= s[0][j] != s[k][j];
				cnt[k] -= s[0][i] != s[k][i];
				cnt[k] -= s[0][j] != s[k][j];
			}

			std::swap(s[0][i], s[0][j]);

			for (int k = 1; k < n; ++ k) {
				st[k][i] += s[0][i] != s[k][i];
				st[k][j] += s[0][j] != s[k][j];
				cnt[k] += s[0][i] != s[k][i];
				cnt[k] += s[0][j] != s[k][j];
			}

			bool flag = true;
			for (int k = 1; k < n; ++ k) {
				if (cnt[k] != 0 && cnt[k] != 2) {
					flag = false;
					break;
				}

				if (cnt[k] == 2) {
					int p1 = 0, p2 = m - 1;
					while (st[k][p1] == 0) {
						++ p1;
					}

					while (st[k][p2] == 0) {
						-- p2;
					}

					if (s[k][p1] != s[0][p2] || s[k][p2] != s[0][p1]) {
						flag = false;
						break;
					}
				} else if (cnt[k] == 0 && !f[k]) {
					flag = false;
					break;
				}
			}

			if (flag) {
				std::cout << s[0] << "\n";
				return;
			}

			for (int k = 1; k < n; ++ k) {
				st[k][i] -= s[0][i] != s[k][i];
				st[k][j] -= s[0][j] != s[k][j];
				cnt[k] -= s[0][i] != s[k][i];
				cnt[k] -= s[0][j] != s[k][j];
			}

			std::swap(s[0][i], s[0][j]);

			for (int k = 1; k < n; ++ k) {
				st[k][i] += s[0][i] != s[k][i];
				st[k][j] += s[0][j] != s[k][j];
				cnt[k] += s[0][i] != s[k][i];
				cnt[k] += s[0][j] != s[k][j];
			}			
		}
	}

	std::cout << -1 << "\n";
}
posted @ 2025-03-15 16:44  maburb  阅读(15)  评论(0)    收藏  举报