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


A. Death Note

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

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

B. Segment Occurrences

题意:给你两个字符串\(s, t\)\(q\)次询问\(s\)的子串\(l, r\)\(t\)出现几次。

前缀和预处理第\(i\)个位置的前缀\(t\)出现几次。

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

    while (q -- ) {
    	int l, r;
    	std::cin >> l >> r;
    	if (r - l + 1 < m) {
    		std::cout << 0 << "\n";
    		continue;
    	}

    	std::cout << sum[r - m + 1] - sum[l - 1] << "\n";
    }
}

C. Vasya And The Mushrooms

题意:一个\(2\times n\)的矩阵,你从左上角出发,需要不重不漏的走完整个矩阵,如果第\(d\)步走到\((i, j)\)可以得到\(d \times a[i][j]\)的价值,求最大价值。

发现路径一定是上下两行切换一段后,一直往右走到\(n\),然后走到另一行一直往左。那么外面预处理后缀,\(sum1_i\)表示从\((1, i)\)一直向右然后向下再向左到\((2, i)\)的价值,\(sum2_i\)表示从\((2, i)\)\((1, i)\)的价值,那么\(sum1_i = 2\times (i - 1) \times a[1][i] + (n + m - 1) \times a[2][i] + sum1_{i+1} - suf\),其中\(suf\)表示\(i\)后面的两行所有元素的和,\(sum2\)的转移同理。
那么外面就可以枚举前缀走上下两行的路径走到哪里,然后加上后面的价值。

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

    std::vector<i64> sum1(n + 1), sum2(n + 1);
    i64 suf = 0;
    for (int i = n - 1; i >= 0; -- i) {
    	sum1[i] = sum1[i + 1] - suf;
    	sum1[i] += (i64)(2 * i) * a[0][i] + (i64)(2 * n - 1) * a[1][i];
    	suf += a[0][i] + a[1][i];
    }

    suf = 0;
    for (int i = n - 1; i >= 0; -- i) {
    	sum2[i] = sum2[i + 1] - suf;
    	sum2[i] += (i64)(2 * n - 1) * a[0][i] + (i64)(2 * i) * a[1][i];
    	suf += a[0][i] + a[1][i];	
    }

    i64 ans = sum1[0], pre = 0;
    for (int i = 0, d = 0; i < n; ++ i) {
    	if (i % 2 == 0) {
    		pre += (i64)d * a[0][i];
    		++ d;
    		pre += (i64)d * a[1][i];
    		++ d;
	    	ans = std::max(ans, pre + sum2[i + 1]);
    	} else {
    		pre += (i64)d * a[1][i];
    		++ d;
    		pre += (i64)d * a[0][i];
    		++ d;
	    	ans = std::max(ans, pre + sum1[i + 1]);
    	}

    }

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

D. Vasya And The Matrix

题意:你需要构造一个\(n\times m\)的矩阵,使得第\(i\)行的异或和为\(a_i\),第\(j\)列的异或和为\(b_j\)

首先\(a\)的异或和就是所有元素的异或和,同理\(b\)的异或和也是所有元素的异或和,所以先比较这两个相不相等。
然后可以把\(a_1\)\(a_{n-1}\)依次给每行的最后一个元素,\(b_1\)\(b_{m-1}\)依次给每列的最后一个元素,这样我们只有第\(n\)行第\(m\)列没有满足了,可以先算出来满足一个的值,判断和另一个是不是相等。

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

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

	if (suma != sumb) {
		std::cout << "NO\n";
		return;
	}

	std::vector ans(n, std::vector<int>(m));
	for (int i = 0; i + 1 < m; ++ i) {
		ans[n - 1][i] = b[i];
	}

	for (int i = 0; i + 1 < n; ++ i) {
		ans[i][m - 1] = a[i];
	}

	ans[n - 1][m - 1] = (suma ^ a[n - 1]) ^ b[m - 1];
	if ((ans[n - 1][m - 1] ^ sumb ^ b[m - 1]) != a[n - 1]) {
		std::cout << "NO\n";
		return;
	}

	std::cout << "YES\n";
	for (int i = 0; i < n; ++ i) {
		for (int j = 0; j < m; ++ j) {
			std::cout << ans[i][j] << " \n"[j == m - 1];
		}
	}
}
posted @ 2025-03-31 16:01  maburb  阅读(10)  评论(0)    收藏  举报