VP Codeforces Round 897 (Div. 2)

A. green_gold_dog, array and permutation

题意:给你一个数组a,你要构造一个排列b,使得不同的aibi尽可能多。

我们按ai从小到大分配n1,这样aibi一定大于ajbj(ai>aj)

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

    std::vector<int> id(n);
    std::iota(id.begin(), id.end(), 0);
    std::sort(id.begin(), id.end(), [&](int i, int j) {
    	return a[i] > a[j];
    });

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

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

B. XOR Palindromes

题意:给你一个长度为n01串,问你对于每个x[1,i],能否有一个恰好有x101串和这个串异或后是回文串。

我们先看原串两边有几个不一样的,假设为cnt,那么x至少大于等于cnt。如果n是偶数,那么我们考虑每次两边同时变回文对应位置的,那么(xcnt)2<=n2cnt,如果是奇数,可以让中间的那个选择变也可以不变。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::string s;
    std::cin >> s;
    std::string ans(n + 1, '0');
    int cnt = 0;
    for (int i = 0; i < n / 2; ++ i) {
    	cnt += s[i] != s[n - 1 - i];
    }

    for (int i = cnt, j = cnt; j <= n / 2; i += 2, ++ j) {
    	ans[i] = '1';
    	if (n % 2 && i + 1 <= n) {
    		ans[i + 1] = '1';
    	}
    }

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

C. Salyg1n and the MEX Game

题意:交互题。有一个集合,每次Alice加入一个数,Bob减去一个数。每次Bob减去的数小于Alice减去的数。问最后mex最大时多少。‘

诈骗题。假设我们已经让mex最大了,那此时Bob删掉一个数我们应该马上再加回来。然后发现我们只有第一次操作有机会让mex变大。所以第一次加入当前mex,后面Bob删什么我们加什么。

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

    std::set<int> s;
    for (int i = 0; i < n; ++ i) {
    	s.insert(a[i]);
    }
    int mex = 0;
    while (s.count(mex)) {
    	++ mex;
    }

	std::cout << mex << std::endl;
    while (1) {
    	int x;
    	std::cin >> x;
    	if (x == -1) {
    		break;
    	}
    	std::cout << x << std::endl;
    }
}

D. Cyclic Operations

题意:你有一个全零的数组,你要让他变成b,每次可以选择一个长度为k的序列l,序列里的数两两不同,然后让ali=l(i+1)%k+1。问能不能变成b

观察发现,如果我们像每个位置要变的数连边,那么会形成一个环,因为每个位置只能连一条出边,所以每条边只在一个环里。也有没在环里的点,但他最终会指向环,这种从环里面搞一些数来配合他就能填好。然后我们考虑怎么填好环里的数。发现如果环的大小不是k,则无法填好。于是判断每个环的大小即可。注意特判k=1的情况。

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

    if (k == 1) {
    	for (int i = 0; i < n; ++ i) {
    		if (a[i] != i) {
    			std::cout << "NO\n";
    			return;
    		}
    	}

    	std::cout << "YES\n";
    	return;
    }

    std::vector<int> st(n, -1), b(n);
    for (int i = 0; i < n; ++ i) {
    	if (st[i] == -1) {
    		int j = i;
    		int cnt = 0;
    		while (st[j] == -1) {
    			st[j] = i;
    			b[j] = cnt;
    			j = a[j];
    			++ cnt;
    		}
    		if (st[j] == i && cnt - b[j] != k) {
    			std::cout << "NO\n";
    			return;
    		}
    	}
    }

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

E1/E2 Salyg1n and Array

题意:交互题。有一个数组a,你要求它的所有数的异或值。 你每次可以询问一个i,它会返回aiai+1...ai+k1。然后会翻转[i,i+k1]这个区间。E1最多问100次,E2最多问57次。

如果k|n,那么我们直接询问每个长度为k的区间就好了。
否则,因为nk都是偶数,那么n%k也是偶数,我们可以每次问剩下的一半。我们先问以前一半结尾的长度为k的区间,我们得到了前一半的异或和,但是前面有kn%k2个数重复异或了,但不用担心,因为这个区间翻转或这些数和后一半挨在一起了我们再询问最后k个数,就得到了后一半的值,并且把重复异或的数再异或了一次。

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

void solve() {
    int n, k;
    std::cin >> n >> k;
    int ans = 0;
    for (int i = 1; i <= n - k + 1; i += k) {
    	ans ^= ask(i);
    }

    if (n % k == 0) {
    	std::cout << "! " << ans << std::endl;
    	return;
    }

    int len = n % k;
    ans ^= ask(n - len / 2 - k + 1);
    ans ^= ask(n - k + 1);
    std::cout << "! " << ans << std::endl;
}
posted @   maburb  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示