VP CodeTON Round 7 (Div. 1 + Div. 2, Rated, Prizes!)

A. Jagged Swaps

题意:给你一个排列,你每次可以选择一个\(i\), 满足\(a_i > a_{i-1}\)\(a_i > a_{i+1}\),然后交换\(a_i\)\(a_{i+1}\)。 问能不能给数组升序排列。

显然第一个不能动,所以它一定得是\(1\)。在满足这条件后,我们假设\([1, i]\)已经是升序(不一定是最小的\(i\)个数在里面),那么对于第\(i+1\)个数,如果它大于\(a_i\)我们可以把它接在后面,否则我们让他一直往前移,就类似与冒泡排序,这样我们就对\([1, i + 1]\)进行了排序,于是可得最终可以对\([1, n]\)进行排序。所以如果\(a_1\)等于\(1\),那么YES,否则NO。

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

    if (a[0] == 1) {
    	std::cout << "YES\n";
    } else {
    	std::cout << "NO\n";
    }
}

B. AB Flipping

题意:给你一个只包含\(AB\)的字符串,你每次可以选择一个\(i\), 满足\(s_i = A, s_{i+1} = B\), 然后交换这两个位置上字符,每个位置只能执行一次交换操作,问最多交换多少次。

最前面的\(A\)和最后面的\(B\)之间的位置都可以执行操作,因为对于第\(i\)个位置,如果他不能操作,那么可以把他后面的\(B\)交换下来,和他操作。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::string s;
    std::cin >> s;

    int l = 0, r = n - 1;
    while (l < n && s[l] == 'B') {
    	++ l;
    }

    while (r >= 0 && s[r] == 'A') {
    	-- r;
    }

    std::cout << std::max(0, r - l) << "\n";
}

C. Matching Arrays

题意:给你两个数组\(a, b\),你要重新排列\(b\),使得\(\sum_{i=1}^{n} a_i > b_i\)正好是\(x\)

我们给两个数组排好序,那么应该让\(A\)\([n - x + 1, n]\)个最大的数和\(B\)\([1, x]\)个最小的数匹配,如果这样还不能匹配\(x\)个,那么没有答案,因为你这些数不能匹配,换一个其他数来肯定也不能匹配。 那么我们接下来要让剩下的\(n - x\)个位置都不匹配,直接让两个数组剩下的数从小到大匹配就行了,因为如果有一个匹配的话,你拿它和比它小的换,换过去的哪个位置的数一定比它小,拿它换比它大的数,这个数依旧比它这个位置上的数大。

点击查看代码
void solve() {
    int n, m;
    std::cin >> n >> m;
    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::sort(b.begin(), b.end());
    std::vector<std::pair<int, int> > c;
    for (int i = 0; i < n; ++ i) {
    	c.push_back({a[i], i});
    }

    std::sort(c.begin(), c.end());
    std::vector<int> ans(n);
    for (int i = n - m, j = 0; i < n; ++ i, ++ j) {
    	ans[c[i].second] = b[j];
    }

    for (int i = 0, j = m; i < n - m; ++ i, ++ j) {
    	ans[c[i].second] = b[j];
    }

    int cnt = 0;
    for (int i = 0; i < n; ++ i) {
    	cnt += a[i] > ans[i];
    }

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

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

D. Ones and Twos

题意:给你一个只包含\(1\)\(2\)的数组,每次会问你有没有一个子数组的和等于\(x\)或着修改一个位置上的数。

应该是这道题变过来的 https://www.luogu.com.cn/problem/P3514
如果有区间的和为\(x\),那么也一定有区间和为\(x-2\),因为假设这个\(x\)这个区间为\([l, r]\),那么如果\(l\)或者\(r\)这个位置是\(2\),显然区间缩小一位和就是\(x-2\),否则两边都是\(1\)那么两边都缩一位一样是\(x-2\)。所以我们只要找最大的奇数和最大的偶数就行。
我们最大的奇数或偶数有一个一定是\(sum_{1n}\),另一个最大的我们只要从两边减去一个奇数就行,于是我们存所有\(1\)的位置,每次找最左边的\(1\)和最右边的\(1\)比较哪边减去的值小,就可以得到另一个最大的数。

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

    int sum = std::accumulate(a.begin(), a.end(), 0);
    std::set<int> s;
    for (int i = 0; i < n; ++ i) {
    	if (a[i] == 1) {
    		s.insert(i);
    	}
    }

    while (q -- ) {
    	int op, x, y;
    	std::cin >> op >> x;;
    	if (op == 1) {
    		int max[2] = {};
    		max[sum & 1] = sum;
    		if (s.empty()) {
    			max[~sum & 1] = -1;
    		} else {
    			int l = *s.begin() * 2 + 1, r = (n - 1 - *s.rbegin()) * 2 + 1;
    			max[~sum & 1] = sum - std::min(l, r);
    		}

    		if (max[x & 1] >= x) {
    			std::cout << "YES\n";
    		} else {
    			std::cout << "NO\n";
    		}
    	} else {
    		std::cin >> y;
    		-- x;
    		s.erase(x);
    		sum -= a[x];
    		a[x] = y;
    		sum += a[x];
    		if (a[x] == 1) {
    			s.insert(x);
    		}
    	}
    }
}

E. Permutation Sorting

题意:给你应该排列,要让所有\(i = a_i\),每次把不满足条件位置上的数拿出来循环右移一下,问\(a_i\)什么时候等于\(i\)

每个数要去的地方是固定的,我们可以找出来,设\(x\)\(i\),它的目标是\(j\),那么如果有其他数在\([i, j]\)之间出发,并且目的地也在\([i, j]\)之间,那么\(x\)就可以少移动一位,因为这个数不会堵到他前面了,本来是一位一位移,现在前面少了一位,就可以少走一步。
因为它是一个环,所有我们破环成链,把这个移动序列延长两倍,然后求出每个数的起点和终点,那么就变成对于每个\([x_i, y_i]\),有多少\(x_j > x_i\)并且\(y_j < y_i\)的,我们按\(x\)排序,从大到小做,用树状数组维护\(y\)的前缀和就行。

点击查看代码
struct Fenwick {
	int n;
	std::vector<int> tr;
	Fenwick(int _n) : n(_n) {
		tr.assign(_n + 1, 0);
	}

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

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

		return res;
	}

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

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

    std::vector<int> ans(n, 1e9);
    std::vector<std::pair<int, int> > b, c;
    for (int i = 0; i < n; ++ i) {
    	if (a[i] == i) {
    		ans[i] = 0;
    	} else {
    		b.push_back({a[i], i});
    	}
    }

    int m = b.size();
    for (int i = 0; i < m; ++ i) {
    	b.push_back(b[i]);
    }

    std::vector<int> val(2 * m + 1), suf(n, 1e9);
    std::vector<std::array<int, 3> >  Q;
    for (int i = 2 * m - 1; i >= 0; -- i) {
    	if (suf[b[i].first] != 1e9) {
    		val[i + 1] = suf[b[i].first] - i;
    		Q.push_back({i + 1, suf[b[i].first] + 1, b[i].first});
    	}
    	suf[b[i].second] = i;
    }

    std::sort(Q.begin(), Q.end(), std::greater<std::array<int, 3> >());
    Fenwick tr(2 * m);
    for (auto & [l, r, id] : Q) {
    	ans[id] = r - l - tr.query(r);
    	tr.modify(r, 1);
    }

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