Codeforces Round 1042 (Div. 3)


A. Lever

题意:balabala

输出\(\sum_{i=1}^{n} \max(0, a_i - b_i)) + 1\)

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

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

	for (int i = 0; i < n; ++ i) {
		std::cin >> b[i];
	}

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

int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	int t = 1;
	std::cin >> t;
	while (t -- ) {
		solve();
	}
	return 0;
}

B. Alternating Series

题意:构造一个数组,使得每个子数组的和都是正数,且每个数加上绝对值后构造的数组的字典序最小。

\(n\)为奇数构造\(-1, 3, -1, 3, ... ,-1\)
偶数构造\(-1, 3, -1, 3, ... , -1, 2\)

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

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

	if (n % 2 == 0) {
		a.back() = 2;
	}

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

int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	int t = 1;
	std::cin >> t;
	while (t -- ) {
		solve();
	}
	return 0;
}

C. Make it Equal

题意:两个多重集合\(S, T\)。你每次可以把\(S\)有一个数\(x\)换成\(|x - k|\)\(x + k\)。可以操作任意次,求能不能使得两个集合相等。

如果限制\(x \geq k\)的情况才能\(x - k\),那么\(x\)可以变成所有模\(k\)等于\(x \mod k\)的数,换句话说就是模\(k\)相同的可以互相转换。如何观察对于一个\(x < k\)的数进行\(|x - k|\),就变成了\(k - x\)。也就是说,模\(k\)等于\(x\)的数和模\(k\)等于\(k - x\)的数可以互相转换。

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

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

	for (int i = 0; i < n; ++ i) {
		std::cin >> b[i];
	}

	std::map<int, int> cnta, cntb;
	for (auto & x : a) {
		int y = x % k;
		y = std::min(y, k - y);
		++ cnta[y];
	}

	for (auto & x : b) {
		int y = x % k;
		y = std::min(y, k - y);
		++ cntb[y];
	}

	for (auto & [x, y] : cnta) {
		if (y != cntb[x]) {
			std::cout << "NO\n";
			return;
		}
	}
	std::cout << "YES\n";
}

int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	int t = 1;
	std::cin >> t;
	while (t -- ) {
		solve();
	}
	return 0;
}

D. Arboris Contractio

题意:一棵树,你每次选择一条路径,如何把路径上的边删掉,再把所有点向第一个点连边。目标是使得直径最小,求最小操作数。

直径最小肯定是一个菊花图,也就是有\(n-1\)个叶子。
那么记录总叶子个数\(tot\),如果一个节点\(u\)\(cnt\)个邻居是叶子,那么它操作\(tot - cnt\)次就能使得树变成菊花图。

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

void solve() {
	int n;
	std::cin >> n;
	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);
	}

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

	int cnt = 0;
	for (int i = 0; i < n; ++ i) {
		cnt += adj[i].size() == 1;
	}

	int ans = cnt - 1;
	for (int i = 0; i < n; ++ i) {
		int t = 0;
		for (auto & j : adj[i]) {
			t += adj[j].size() == 1;
		}

		ans = std::min(ans, cnt - t);
	}
	std::cout << ans << "\n";
}

int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	int t = 1;
	std::cin >> t;
	while (t -- ) {
		solve();
	}
	return 0;
}

E. Adjacent XOR

题意:一个数组\(a\),你可以对于每个\(i\)操作\(a_i = a_i \oplus a_{i+1}\),每个\(i\)最多操作一次,顺序任意。求能不能把\(a\)变成\(b\)

如果\(i\)需要找一个右端点\(j\)\([i, j]\)的异或和\(\oplus_{k=i}^{j} a_i = b_i\),那么这个操作肯定是从后往前,则对于\([i + 1, j]\)内的位置,它们找的右端点也只能是\(j\)
\(L_i\)表示需要\([L_i, i]\)的异或和才能变成\(b_{L_i}\)的最小位置。这个可以双指针维护。
然后对于每个\([L_i, i]\)看作一个区间,它们要么相离,要么只在一个端点处相交,否则无解。

点击查看代码
  #include <bits/stdc++.h>

using i64 = long long;

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

	for (int i = 1; i <= n; ++ i) {
		std::cin >> b[i];
	}

	std::vector<int> sum(n + 1);
	for (int i = 1; i <= n; ++ i) {
		sum[i] = sum[i - 1] ^ a[i];
	}

	std::vector<int> L(n + 2);
	std::ranges::iota(L, 0);
	for (int i = 1, j = 1; i <= n; ++ i) {
		j = std::max(i, j);
		while (j <= n && (sum[j] ^ sum[i - 1]) != b[i]) {
			++ j;
			L[j] = std::min(L[j], i);
		}

		if (j > n) {
			std::cout << "NO\n";
			return;
		}
	}

	for (int i = n, min = n; i >= 1; -- i) {
		if (L[i] < min && min < i) {
			std::cout << "NO\n";
			return;
		}
		min = std::min(min, L[i]);
	}
	std::cout << "YES\n";
}

int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	int t = 1;
	std::cin >> t;
	while (t -- ) {
		solve();
	}
	return 0;
}

F. Unjust Binary Life

题意:两个\(01\)\(a, b\),有一个矩阵,第\(i\)\(j\)列的值为\(a_i \oplus b_j\)。对于每个\((x, y)\),可以更改\(a, b\)任意位置的元素,使从\((1, 1)\)出发,每次往右或者往下有一条全\(0\)路径到\((x, y)\)。求所有\((x, y)\)最小操作值的和。

一个重要的观察是,如果想要到\((x, y)\),那么\(a[1...x], b[1...y]\)要么都是\(0\)要么都是\(1\)。因为其实每行要么是\(b\),要么是\(b\)每个位置反转的后的值。如果不是全\(0\)或全\(1\)\((1, 1)\)\((x, y)\)必然不联通。
那么具体是取\(0\)号还是\(1\)好?记\(cntA0\)\(a\)的前缀\(0\)的个数,\(cntA1\)代表\(a\)前缀\(1\)的个数,\(cntB0, cntB1\)同理代表\(b\)。我们先全部选\(1\),那么需要把\(0\)都改成\(1\),那么贡献是\(\sum_{i=1}^{n} \sum_{j=1}^{n} cntA0_i + cntB0_j\)。然后考虑如果把\((i, j)\)改为全\(0\),贡献变为\(cntA0_i - cntA1_i + cntB0_j - cntB1_j = cntA0_i - (i - cntA0_i) + cntB0_j - (j - cntB0_j) = 2\times cntA0_i - i + 2\times cntB0_j - j\)。把所有\(2\times cntA0_i,i + 2\times cntB0_j - j\)分别存到两个数组里然后排序。然后对于每个\(i\)需要找\(2\times cntA0_i - i + 2\times cntB0_j - j > 0\)的位置,因为已经排序好了,可以直接二分。

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

void solve() {
	int n;
	std::cin >> n;
	std::string a, b;
	std::cin >> a >> b;

	std::vector<int> sa(n), sb(n);
	for (int i = 0; i < n; ++ i) {
		sa[i] = a[i] == '0';
		if (i) {
			sa[i] += sa[i - 1];
		}
	}

	for (int i = 0; i < n; ++ i) {
		sb[i] = b[i] == '0';
		if (i) {
			sb[i] += sb[i - 1];
		}
	}

	i64 ans = std::accumulate(sa.begin(), sa.end(), 0ll) * n +
				 std::accumulate(sb.begin(), sb.end(), 0ll) * n;
	std::vector<int> A(n), B(n);
	for (int i = 0; i < n; ++ i) {
		A[i] = 2 * sa[i] - (i + 1);
		B[i] = 2 * sb[i] - (i + 1);
	}	

	std::ranges::sort(A);
	std::ranges::sort(B);
	std::vector<i64> sum(n + 1);
	for (int i = n - 1; i >= 0; -- i) {
		sum[i] = sum[i + 1] + B[i];
	}

	for (int i = 0; i < n; ++ i) {
		//A[i] + B[i] > 0;
		//B[i] > -A[i];
		int p = std::ranges::upper_bound(B, -A[i]) - B.begin();
		ans -= sum[p] + (i64)(n - p) * A[i];
	}
	std::cout << ans << "\n";
}

int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	int t = 1;
	std::cin >> t;
	while (t -- ) {
		solve();
	}
	return 0;
}

G. Wafu!

题意:一个集合,一开始分数为\(1\),每次把集合最小的数\(m\)拿出来,分数乘上\(m\),然后把\([1, m)\)的数插入集合。操作\(k\)次后分数为多少。

手玩一下,发现如果想要把\([1, i]\)的数都消完,需要的步数是每次翻倍的。
那么观察一下性质,记\(f_i\)为把\([1, i]\)消完需要的操作次数,那么首先需要把\([1, i - 1]\)消完,然后消掉\(i\),然后会插入\([1, i)\),次数需要再消一次\([1, i - 1]\),那么\(f_i = 2\times f_{i-1} + 1\)\(k\)最多只有\(1e9\),也就是\(i \geq 30\)次数就超过\(k\)了。如果发现\(k \geq f_i\),也就是可以消掉\([1, i]\),其对答案的贡献是多少呢,记\(g_i\)为消掉\([1, i]\)得到的乘积,那么同理得\(g_i = g_{i-1}^2 \times i\)
于是就可以模拟了,每次取出最小值\(m\),我们要把小于等于它的都消掉,那么消掉\(m\)操作一次,然后消掉\([1, m - 1]\)需要操作\(f_{m-1}\)次,总共\(f_{m-1} + 1\)次。如果不够,就模拟一次,把\([1, m - 1]\)插入。

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

template<class T>
constexpr T power(T a, i64 b) {
    T res = 1;
    for (; b; b /= 2, a *= a) {
        if (b % 2) {
            res *= a;
        }
    }
    return res;
}

constexpr i64 mul(i64 a, i64 b, i64 p) {
    i64 res = a * b - i64(1.L * a * b / p) * p;
    res %= p;
    if (res < 0) {
        res += p;
    }
    return res;
}
template<i64 P>
struct MLong {
    i64 x;
    constexpr MLong() : x{} {}
    constexpr MLong(i64 x) : x{norm(x % getMod())} {}
    
    static i64 Mod;
    constexpr static i64 getMod() {
        if (P > 0) {
            return P;
        } else {
            return Mod;
        }
    }
    constexpr static void setMod(i64 Mod_) {
        Mod = Mod_;
    }
    constexpr i64 norm(i64 x) const {
        if (x < 0) {
            x += getMod();
        }
        if (x >= getMod()) {
            x -= getMod();
        }
        return x;
    }
    constexpr i64 val() const {
        return x;
    }
    explicit constexpr operator i64() const {
        return x;
    }
    constexpr MLong operator-() const {
        MLong res;
        res.x = norm(getMod() - x);
        return res;
    }
    constexpr MLong inv() const {
        assert(x != 0);
        return power(*this, getMod() - 2);
    }
    constexpr MLong &operator*=(MLong rhs) & {
        x = mul(x, rhs.x, getMod());
        return *this;
    }
    constexpr MLong &operator+=(MLong rhs) & {
        x = norm(x + rhs.x);
        return *this;
    }
    constexpr MLong &operator-=(MLong rhs) & {
        x = norm(x - rhs.x);
        return *this;
    }
    constexpr MLong &operator/=(MLong rhs) & {
        return *this *= rhs.inv();
    }
    friend constexpr MLong operator*(MLong lhs, MLong rhs) {
        MLong res = lhs;
        res *= rhs;
        return res;
    }
    friend constexpr MLong operator+(MLong lhs, MLong rhs) {
        MLong res = lhs;
        res += rhs;
        return res;
    }
    friend constexpr MLong operator-(MLong lhs, MLong rhs) {
        MLong res = lhs;
        res -= rhs;
        return res;
    }
    friend constexpr MLong operator/(MLong lhs, MLong rhs) {
        MLong res = lhs;
        res /= rhs;
        return res;
    }
    friend constexpr std::istream &operator>>(std::istream &is, MLong &a) {
        i64 v;
        is >> v;
        a = MLong(v);
        return is;
    }
    friend constexpr std::ostream &operator<<(std::ostream &os, const MLong &a) {
        return os << a.val();
    }
    friend constexpr bool operator==(MLong lhs, MLong rhs) {
        return lhs.val() == rhs.val();
    }
    friend constexpr bool operator!=(MLong lhs, MLong rhs) {
        return lhs.val() != rhs.val();
    }
};

template<>
i64 MLong<0LL>::Mod = i64(1E18) + 9;

template<int P>
struct MInt {
    int x;
    constexpr MInt() : x{} {}
    constexpr MInt(i64 x) : x{norm(x % getMod())} {}
    
    static int Mod;
    constexpr static int getMod() {
        if (P > 0) {
            return P;
        } else {
            return Mod;
        }
    }
    constexpr static void setMod(int Mod_) {
        Mod = Mod_;
    }
    constexpr int norm(int x) const {
        if (x < 0) {
            x += getMod();
        }
        if (x >= getMod()) {
            x -= getMod();
        }
        return x;
    }
    constexpr int val() const {
        return x;
    }
    explicit constexpr operator int() const {
        return x;
    }
    constexpr MInt operator-() const {
        MInt res;
        res.x = norm(getMod() - x);
        return res;
    }
    constexpr MInt inv() const {
        assert(x != 0);
        return power(*this, getMod() - 2);
    }
    constexpr MInt &operator*=(MInt rhs) & {
        x = 1LL * x * rhs.x % getMod();
        return *this;
    }
    constexpr MInt &operator+=(MInt rhs) & {
        x = norm(x + rhs.x);
        return *this;
    }
    constexpr MInt &operator-=(MInt rhs) & {
        x = norm(x - rhs.x);
        return *this;
    }
    constexpr MInt &operator/=(MInt rhs) & {
        return *this *= rhs.inv();
    }
    friend constexpr MInt operator*(MInt lhs, MInt rhs) {
        MInt res = lhs;
        res *= rhs;
        return res;
    }
    friend constexpr MInt operator+(MInt lhs, MInt rhs) {
        MInt res = lhs;
        res += rhs;
        return res;
    }
    friend constexpr MInt operator-(MInt lhs, MInt rhs) {
        MInt res = lhs;
        res -= rhs;
        return res;
    }
    friend constexpr MInt operator/(MInt lhs, MInt rhs) {
        MInt res = lhs;
        res /= rhs;
        return res;
    }
    friend constexpr std::istream &operator>>(std::istream &is, MInt &a) {
        i64 v;
        is >> v;
        a = MInt(v);
        return is;
    }
    friend constexpr std::ostream &operator<<(std::ostream &os, const MInt &a) {
        return os << a.val();
    }
    friend constexpr bool operator==(MInt lhs, MInt rhs) {
        return lhs.val() == rhs.val();
    }
    friend constexpr bool operator!=(MInt lhs, MInt rhs) {
        return lhs.val() != rhs.val();
    }
};

template<>
int MInt<0>::Mod = 998244353;

template<int V, int P>
constexpr MInt<P> CInv = MInt<P>(V).inv();

constexpr int P = 1000000007;
using Z = MInt<P>;

i64 f[50];
Z g[50];
int m = 0;

void init() {
    m = 1;
    g[0] = 1;
    f[0] = 0;
    for (; ; ++ m) {
        f[m] = 2 * f[m - 1] + 1;
        g[m] = g[m - 1] * g[m - 1] * m;
        if (f[m] >= 1e9) {
            break;
        }
    }
}

void solve() {
	int n, k;
	std::cin >> n >> k;
	std::set<int> s;
	for (int i = 0; i < n; ++ i) {
		int x;
		std::cin >> x;
		s.insert(x);
	}

    Z ans = 1;
    while (s.size() && k) {
        int x = *s.begin();
        s.erase(s.begin());
        if (x <= m && k >= f[x - 1] + 1) {
            ans *= g[x - 1] * x;
            k -= f[x - 1] + 1;
        } else {
            ans *= x;
            for (int i = 1; i < std::min(m + 1, x); ++ i) {
                s.insert(i);
            }
            -- k;
        }
    }
    std::cout << ans << "\n";
}

int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	int t = 1;
    init();
	std::cin >> t;
	while (t -- ) {
		solve();
	}
	return 0;
}
posted @ 2025-08-11 13:51  maburb  阅读(609)  评论(0)    收藏  举报