VP Codeforces Round 983 (Div. 2)


A. Circuit

题意:有\(n\)个灯和\(2n\)个开关,每个开关控制一个灯,每个灯被两个开关控制,如果控制一个灯的两个开关中恰好有一个打开,这个灯就会亮。你不知道具体哪些开关控制哪些灯。现在给你\(2n\)个灯的开关状态,求最少亮多少灯和最多亮多少灯。

最少的状态就是尽量让两个打开的开关控制一个灯,设有\(cnt\)个开关打开了,那么最小数就是\(cnt \% 2\)
如果\(cnt <= n\),那么可以让每个打开的开关控制不同的灯,答案是\(cnt\),否则尽量让最少的灯被两个开关控制,答案是\(n - (cnt - n)\)

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

    int cnt = std::count(a.begin(), a.end(), 1);
    std::cout << cnt % 2 << " ";
    if (cnt <= n) {
    	std::cout << cnt << "\n";
    } else {
    	std::cout << (n - (cnt - n)) << "\n";
    }
}

B. Medians

题意:给你一个序列\(a = \{1, 2, ..., n - 1, n\}\),你要把序列分成\(m\)块,其中\(m\)是奇数。并且每一块的长度都是奇数。最后结果等于每一块的中位数组成的新序列的中位数,你要使得这个数为\(k\)

特判\(n==1\)的情况。
然后如果\(k == 1 || k == n\),则无解。因为\(k\)一定出现在最两侧。
否则看\((k - 1)\)\((n - k)\)是不是奇偶性相同。如果不同的话,左边的块数一定不会等于右边的块数,\(k\)也不可能是中位数。
否则分奇偶讨论即可,保证左右两边块数相同,\(k\)单独占一块。

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

	int ans = n;
    std::sort(a.begin(), a.end());
    for (int i = 0, l = 0, r = 0; i + 1 < n; ++ i) {
    	while (r < n && a[r] < a[i] + a[i + 1]) {
    		++ r;
    	}

    	while (a[l] + a[l + 1] <= a[r - 1]) {
    		++ l;
    	}

    	ans = std::min(ans, l + (n - r));
    }

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

C. Trinity

题意:给你一个数组,你每次可以让其中一个数变成另一个数。你要使得任意三个数都可以组成三角形。求最小操作数。

排序后枚举最小的两个数,因为答案最小,那么这两个数一定是相邻的,双指针维护即可。

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

	int ans = n;
    std::sort(a.begin(), a.end());
    for (int i = 0, l = 0, r = 0; i + 1 < n; ++ i) {
    	while (r < n && a[r] < a[i] + a[i + 1]) {
    		++ r;
    	}

    	while (a[l] + a[l + 1] <= a[r - 1]) {
    		++ l;
    	}

    	ans = std::min(ans, l + (n - r));
    }

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

D. Genokraken

题意:交互题。有一棵树,除了\(0\)号点外其他点都最多有两条边相连。其中\(1\)号点必有儿子,并且如果\(u, v(u < v)\), 则\(fa_u < fa_v\)。你每次询问两个节点得到它们的路径是否经过了\(0\),最多询问\(2n - 6\)次。求出这棵树。

主要利用编号大的节点的父亲更大的性质,从大到小找,每次找\(i\)的父亲,\(i-1\)的父亲一定比\(i\)的编号小,于是可以从\(f_i - 1\)开始找,这样每个点最多被询问一次,总共\(n - 2\)次询问。

点击查看代码
int ask(int a, int b) {
	std::cout << "? " << a << " " << b << std::endl;
	int res;
	std::cin >> res;
	return res;
}

void solve() {
    int n;
    std::cin >> n;
    std::vector<int> ans(n);
    for (int i = n - 1, j = n - 2; i ; -- i) {
    	while (j > 0 && ask(i, j)) {
    		-- j;
    	}

    	if (j > 0) {
    		ans[i] = j;
    		-- j;
    	}
    }
    
    std::cout << "!";
    for (int i = 1; i < n; ++ i) {
    	std::cout << " " << ans[i];
    }
    std::cout << std::endl;
}

E. Balanced

待补

posted @ 2025-02-04 15:57  maburb  阅读(25)  评论(0)    收藏  举报