Educational Codeforces Round 177 (Rated for Div. 2)


A. Cloudberry Jam

题意:每个物品花费2的代价,问\(n\)个物品花费多少代价。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::cout << n * 2 << "\n";
}

B. Large Array and Segments

题意:把\(a\)复制\(k\)份,问有多少下标满足它的后缀和大于等于\(x\)

这题二分会爆\(longlong\)然后\(WA \ test \ 4\)
题目说了\(n, k\)总共不超过\(2e5\)。于是直接枚举过去,先一个数组一个数组的加,直到后缀和大于等于\(x\),然后一个一个数减,减到和小于\(x\)

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

    i64 sum = std::accumulate(a.begin(), a.end(), 0ll);

    int i = 0;
    i64 s = 0;
    for (; i < k && s < x; ++ i) {
    	s += sum;
    }

    int j = 0;
    while (s >= x) {
    	s -= a[j];
    	++ j;
    }

    std::cout << (i64)n * k - ((i64)n * i - j) << "\n";
}

C. Disappearing Permutation

题意:给你一个排序\(p\),每次修改\(d_i\)这个位置为\(0\)。你每次可以选择一个\(i\)使得\(p_i = i\)。问每次修改后把数组恢复为一个排列的最小操作数。

如果修改了\(i\)这个位置为\(0\),那么我们需要操纵\(i\),那么此时\(p_i\)不存在了,我们需要操纵\(p_i\),同理操纵\(p_i\)\(p_{p_i}\)又没有了,那么我们就一直使得\(i = p_i\), 一直跳到\(p_i\)本来就等于\(i\)的位置就可以停止操作了。

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

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

    std::vector<int> st(n);
    int ans = 0;
    for (int i = 0; i < n; ++ i) {
    	int x = d[i];
    	while (!st[x]) {
    		st[x] = 1;
    		++ ans;
    		x = p[x];
    	}
    	std::cout << ans << " \n"[i == n - 1];
    }
}

D. Even String

题意:构造一个字符串是包含给定数量的字符,并且每个相等的字符要么同时在奇数位置上要么同时在偶数位置上,求方案数。

看起来貌似无从下手。
但我尝试暴力\(dp\)直接就够了。
\(f[i][j]\)为奇数位置用了\(i\)个偶数位置用了\(j\)个方案数,那么对于一个有\(cnt\)数量的字符,可以转移到\(f[i + cnt][j] += C(odd - i, cnt) * f[i][j], f[i][j + cnt] += C(even - j) * f[i][j]\)。其中\(odd, even\)分别是奇数位置的总数和偶数位置的总数。然后答案是\(f[odd][even]\)
代码省略取模类。

点击查看代码
struct Comb {
    int n;
    std::vector<Z> _fac;
    std::vector<Z> _invfac;
    std::vector<Z> _inv;
    
    Comb() : n{0}, _fac{1}, _invfac{1}, _inv{0} {}
    Comb(int n) : Comb() {
        init(n);
    }
    
    void init(int m) {
        if (m <= n) return;
        _fac.resize(m + 1);
        _invfac.resize(m + 1);
        _inv.resize(m + 1);
        
        for (int i = n + 1; i <= m; i++) {
            _fac[i] = _fac[i - 1] * i;
        }
        _invfac[m] = _fac[m].inv();
        for (int i = m; i > n; i--) {
            _invfac[i - 1] = _invfac[i] * i;
            _inv[i] = _invfac[i] * _fac[i - 1];
        }
        n = m;
    }
    
    Z fac(int m) {
        if (m > n) init(2 * m);
        return _fac[m];
    }
    Z invfac(int m) {
        if (m > n) init(2 * m);
        return _invfac[m];
    }
    Z inv(int m) {
        if (m > n) init(2 * m);
        return _inv[m];
    }
    Z binom(int n, int m) {
        if (n < m || m < 0) return 0;
        return fac(n) * invfac(m) * invfac(n - m);
    }
} comb;

void solve() {
    std::array<int, 26> cnt{};
    for (int i = 0; i < 26; ++ i) {
    	std::cin >> cnt[i];
    }

    int m = std::accumulate(cnt.begin(), cnt.end(), 0);
    int odd = (m + 1) / 2, even = m / 2;
    std::map<std::pair<int, int>, Z> f;
    f[{0, 0}] = 1;
    for (int i = 0; i < 26; ++ i) {
    	if (!cnt[i]) {
    		continue;
    	}

	    std::map<std::pair<int, int>, Z> g;
	    for (auto & [it, v] : f) {
	    	auto & [x, y] = it;
	    	if (x + cnt[i] <= odd) {
	    		g[{x + cnt[i], y}] += comb.binom(odd - x, cnt[i]) * v;
	    	}

	    	if (y + cnt[i] <= even) {
	    		g[{x, y + cnt[i]}] += comb.binom(even - y, cnt[i]) * v;
	    	}
	    }

	    f = g;
    }

    std::cout << f[{odd, even}] << "\n";
}
posted @ 2025-04-04 00:36  maburb  阅读(484)  评论(0)    收藏  举报