VP Educational Codeforces Round 18


A. New Bus Route

题意:给你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::sort(a.begin(), a.end());
	int ans = 2e9, cnt = 0;
	for (int i = 1; i < n; ++ i) {
		if (a[i] - a[i - 1] < ans) {
			ans = a[i] - a[i - 1];
			cnt = 1;
		} else if (a[i] - a[i - 1] == ans) {
			++ cnt;
		}
	}

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

B. Counting-out Rhyme

题意:每次以一个人为起点,在环里走ai下把数到的那个人删掉,然后下一个人变成起点。求被删掉的人。

模拟题,ai大于等于n的时候取模就行了,因为每走n次就走回来了。

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

    std::vector<int> b(n);
    std::iota(b.begin(), b.end(), 0);
    for (int i = 0; i < k; ++ i, -- n) {
    	int p = a[i] % n;
    	std::cout << b[p] + 1 << " \n"[i == k - 1];
    	std::vector<int> c(b.begin() + p + 1, b.end());
    	for (int j = 0; j < p; ++ j) {
    		c.push_back(b[j]);
    	}
    	b = c;
    }
}

C. Divide by Three

题意:给你一个大数,你要删去一些数使得这个数没有前导零且是3的倍数。

3的倍数就是每一位加起来是3的倍数。
那么我们考虑dpf[i][j]表示到i位模3等于j最少要删掉几个。转移就是枚举这个数要不要删。注意如果这一位是0且转移过来的把前面都删了就不要转移。

点击查看代码
void solve() {
    std::string s;
    std::cin >> s;
    int n = s.size();
    const int inf = 1e9;
    std::vector f(n + 1, std::vector<int>(3, inf));
    std::vector pre(n + 1, std::vector<int>(3, -1));
    f[0][0] = 0;

    auto change = [&](int i, int j, int x, int y, int v) -> void {
    	if (f[i][j] + v < f[x][y]) {
    		f[x][y] = f[i][j] + v;
    		pre[x][y] = j;
    	}
    };	

    for (int i = 0; i < n; ++ i) {
    	int d = s[i] - '0';
    	for (int j = 0; j < 3; ++ j) {
    		change(i, j, i + 1, j, 1);
    		if (d == 0 && f[i][j] == i) {
    			continue;
    		}
    		change(i, j, i + 1, (j + d) % 3, 0);
    	}
    }

    if (f[n][0] >= n) {
    	if (s.find('0') != s.npos) {
    		std::cout << "0\n";
    	} else {
	    	std::cout << -1 << "\n";
    	}
    	return;
    }

    std::string ans;
    for (int i = n, j = 0; i ; -- i) {
    	if (f[i][j] == f[i - 1][pre[i][j]]) {
    		ans += s[i - 1];
    	}

    	j = pre[i][j];
    }

    while (ans.size() > 1 && ans.back() == '0') {
    	ans.pop_back();
    }

    if (ans.empty()) {
    	std::cout << -1 << "\n";
    	return;
    }

    std::reverse(ans.begin(), ans.end());
	std::cout << ans << "\n";
}

D. Paths in a Complete Binary Tree

题意:一棵满二叉树,每个节点的编号就是这个点在中序遍历时的时间戳。给出一个操作序列,从某个位置往上往左往右走,求最后到哪个点。

找规律题。首先发现每一层数的编号是一个等差序列,第i层最小的点是2ni,公差为2ni+1,其中n是总层数。那么这一层的数只需要求自己的lowbit就能求出这一层最小的数,因为这一层的数是若干个2ni+1加上一个2ni,容易发现ni位一定是1。然后上下就可以根据层来讨论,先看是左节点还是右节点,左节点往上是加2ni1,右节点往上是减2ni1,往下讨论同理。于是模拟就行。

点击查看代码
void solve() {
    i64 n, q;
    std::cin >> n >> q;
    while (q -- ) {
    	i64 x;
    	std::cin >> x;
    	i64 y = x & -x;
    	std::string s;
    	std::cin >> s;
    	for (auto & c : s) {
    		if (c == 'U') {
    			if (y * 2 == n + 1) {
    				continue;
    			} else {
    				if ((x - y) / (y * 2) % 2 == 0) {
    					x += y;
    				} else {
    					x -= y;
    				}

    				y *= 2;
    			}
    		} else if (c == 'L') {
    			if (x & 1) {
    				continue;
    			} else {
    				x -= y / 2;
    				y /= 2;
    			}
    		} else {
    			if (x & 1) {
    				continue;
    			} else {
    				x += y / 2;
    				y /= 2;
    			}
    		}
    	}

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

E. Colored Balls

题意:n个数,你要选一个x把每个数分成若干个xx+1,求所有数分成的部分总数最少。

如果一个x是合法的,则对于每个i都满足ai%xaix,这表示我把aix个分组,然后多出来ai%x个,这些就要放到x里变成x+1,所以多出来的不能大于x的个数。
假设a1是最小的,那么x肯定小于等于a1,那么我们可以枚举a1被分成了几组,然后检查合不合法,那么如果ai分成k,则有x=aik,检查是不是合法的,然后更新答案就行。

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

    std::sort(a.begin(), a.end());

    const i64 inf = 1e18;
    auto check = [&](int k) -> i64 {
    	if (k <= 0) {
    		return inf;
    	}
    	i64 sum = 0;
    	for (int i = 0; i < n; ++ i) {
    		if (a[i] % k > a[i] / k) {
    			return inf;
    		}
    		sum += (a[i] + k) / (k + 1);
    	}

    	return sum;
    };

    i64 ans = inf;
    for (int i = 1; i <= a[0] / i; ++ i) {
    	ans = std::min({ans, check(i), check(i - 1)});
    	ans = std::min({ans, check(a[0] / i),  check(a[0] / i - 1)});
    }

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