VP Codeforces Round 877 (Div. 2)


A. Blackboard List

题意:一开始有两个数,然后每次选择两个数的差的绝对值插入进来,最后有\(n\)个数。求一个可能的一开始的数。

如果全是正数,显然最大数不可能是其它数的差,那么它是一开始的数。
如果有负数,因为是插入绝对值,所以负数不可能是后面插入的,它是一开始的数。

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

	std::ranges::sort(a);
	if (a[0] < 0) {
		std::cout << a[0] << "\n";
	} else {
		std::cout << a.back() << "\n";
	}
}

B. Minimize Permutation Subarrays

题意:一个排列,你要交换两条数一次。使得子排列的个数最少。

应该用\(n\)插在\(1, 2\)之间。

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

    int p1 = std::ranges::find(a, 1) - a.begin();
    int p2 = std::ranges::find(a, 2) - a.begin();
    int pn = std::ranges::find(a, n) - a.begin();
    if (pn > std::max(p1, p2)) {
    	std::cout << std::max(p1, p2) + 1 << " " << pn + 1 << "\n";
    } else  if (pn < std::min(p1, p2)) {
    	std::cout << std::min(p1, p2) + 1 << " " << pn + 1 << "\n"; 
    } else {
    	std::cout << 1 << " " << 1 << "\n";
    }
}

C. No Prime Differences

题意:用\([1, n\times m]\)的数填充一个\(n \times m\)的矩阵,每个数恰好一次。使得任意两个相邻的数的差不是质数。

如果我们按行顺序从小到大填数,那么一行相邻的两个数差是\(1\),一列相邻的两个数差是\(m\),我们可以把奇数行先排一起,偶数行都排后面,这样一列相邻数的差就大于等于\(2m\)。但特殊情况是\(n=4\)的情况,这时我们一列一列填就行。

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

	    for (int i = 1; i < n; i += 2) {
	    	for (int j = 0; j < m; ++ j) {
	    		a[i][j] = k ++ ;
	    	}
	    }
    } else {
    	for (int j = 0; j < m; ++ j) {
    		for (int i = 0; i < n; ++ i) {
    			a[i][j] = k ++ ;
    		}
    	}
    }

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

D. Bracket Walk

题意:一个括号序列是好的,是从左开始遍历这个序列,每次可以往左或者往右,把当前位置的括号插入到序列里,最后遍历到最后一个字符出来时的序列时合法的括号序列这个序列就是好的。每次修改一个位置的字符,求这个序列是不是好的。

显然如果想要影响括号的合法性,只有连续出现的两个相同字符可以做到。我们可以利用这两个相同的字符无限制造这类字符。
首先\(n\)是奇数,不过怎么走括号序列长度都是奇数,肯定不合法。如果第一个括号不是左括号,最后一个不是右括号,不合法。
否则如果没有连续的两个相同括号出现,那么一定是左括号右括号交替出现,合法。然后我们分左括号右括号记录连续出现的括号的位置。如果合法需要满足第一个连续出现的是左括号和最后一个出现的是右括号。

点击查看代码
void solve() {
    int n, m;
    std::cin >> n >> m;
    std::string s;
    std::cin >> s;
    std::set<int> s1, s2;
    for (int i = 0; i < n; ++ i) {
    	if (i + 1 < n && s[i] == '(' && s[i + 1] == '(') {
    		s1.insert(i);
    	}

    	if (i + 1 < n && s[i] == ')' && s[i + 1] == ')') {
    		s2.insert(i);
    	}
    }

    while (m -- ) {
    	int p;
    	std::cin >> p;
    	if (n & 1) {
    		std::cout << "NO\n";
    		continue;
    	}
    	-- p;
    	if (s[p] == '(') {
    		if (p) {
    			s1.erase(p - 1);
    			if (s[p - 1] == ')') {
    				s2.insert(p - 1);
    			}
    		}

    		if (p + 1 < n) {
    			s1.erase(p);
    			if (s[p + 1] == ')') {
    				s2.insert(p);
    			}
    		}

    		s[p] = ')';
    	} else {
    		if (p) {
    			s2.erase(p - 1);
    			if (s[p - 1] == '(') {
    				s1.insert(p - 1);
    			}
    		}

    		if (p + 1 < n) {
    			s2.erase(p);
    			if (s[p + 1] == '(') {
    				s1.insert(p);
    			}
    		}
    		s[p] = '(';
    	}

    	if (s[0] == ')' || s.back() == '(') {
    		std::cout << "NO\n";
    	} else if (s1.empty() && s2.empty()) {
    		std::cout << "YES\n";
    	} else if (s1.empty() || s2.empty()) {
    		std::cout << "NO\n";
    	} else {
    		if (*s1.begin() < *s2.begin() && *s2.rbegin() > *s1.rbegin()) {
    			std::cout << "YES\n";
    		} else {
    			std::cout << "NO\n";
    		}
    	}
    }
}
posted @ 2025-05-13 21:08  maburb  阅读(17)  评论(0)    收藏  举报