VP Educational Codeforces Round 1


开个新坑,听说edu有很多典题,我因为很多次做不出来被别人称为典题的题,所以准备从老到新把edu都vp一遍。


A. Tricky Sum

题意:在1n中的每个数,如果不是2的幂,就减去,否则加上。

先求全部1n的和,然后枚举减去去2的幂就行。

点击查看代码
void solve() {
    i64 n;
    std::cin >> n;
    i64 ans = n * (n + 1) / 2;
    for (i64 i = 1; i <= n; i *= 2) {
    	ans -= i * 2;
    }
    std::cout << ans << "\n";
}

B. Queries on a String

题意:给你一个字符串,多次操作,每次对一个区间l,r右移k次。求最终字符串。

发现字符串长度比较小,可以保留右移。如果右移次数超过区间长度则对区间长度取模,因为右移次数超过了区间长度就会转回来。那么就可以暴力模拟。

点击查看代码
void solve() {
    std::string s;
    std::cin >> s;
    int m;
    std::cin >> m;
    while (m -- ) {
    	int l, r, k;
    	std::cin >> l >> r >> k;
    	-- l, -- r;
    	int n = r - l + 1;
    	k %= n;
    	std::string t = s;
    	for (int i = 0; i < n; ++ i) {
    		t[l + i] = s[l + (i - k + n) % n];
    	}

    	s = t;
    }
    std::cout << s << "\n";
}

C. Nearest vectors

题意:给你n个向量,求任意两对的最小夹角。

思路很简单,用atan2这个函数求角度然后排序就行。但这题比较卡精度,需要开long double

点击查看代码
#define double long double

const double pi = std::acos(-1);

struct Node {
	int id;
	double a;

	bool operator < (Node & n) const {
		return a < n.a;
	}
};

void solve() {
    int n;
    std::cin >> n;
    std::vector<Node> a(n);
    for (int i = 0; i < n; ++ i) {
    	double x, y;
    	std::cin >> x >> y;
    	double angle = std::atan2(y, x);
    	if (angle < 0) {
    		angle += 2 * pi;
    	}

    	a[i] = {i, angle};
    }

    std::sort(a.begin(), a.end());
    double ans = a[0].a - (a[n - 1].a - 2 * pi) , x = a[0].id, y = a[n - 1].id;
    for (int i = 0; i + 1 < n; ++ i) {
    	if (a[i + 1].a - a[i].a < ans) {
    		ans = a[i + 1].a - a[i].a;
    		x = a[i].id, y = a[i + 1].id;
    	}
    }

    std::cout << x + 1 << " " << y + 1 << "\n";
}

D. Igor In the Museum

题意:给你一个矩阵,有些地方是空的,有些地方是墙,你可以上下左右移动。问每个位置可以碰多少墙(墙的每一面单独算)。

直接并查集维护空格的联通块,然后统计墙的个数就行。

点击查看代码
struct DSU {
	std::vector<int> fa, cnt;
	DSU(int _n) {
		init(_n);
	}

	void init(int _n) {
		fa.assign(_n, 0);
		cnt.assign(_n, 1);
		std::iota(fa.begin(), fa.end(), 0);
	}

	int find(int x) {
		return x == fa[x] ? x : fa[x] = find(fa[x]);
	}

	bool merge(int x, int y) {
		x = find(x), y = find(y);
		if (x == y) {
			return false;
		}

		fa[y] = x;
		cnt[x] += cnt[y];
		return true;
	}

	bool same(int x, int y) {
		return find(x) == find(y);
	}

	int size(int x) {
		return cnt[find(x)];
	}
};

void solve() {
    int n, m, k;
    std::cin >> n >> m >> k;
    std::vector<std::string> s(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> s[i];
    }

    const int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
    auto get = [&](int i, int j) -> int {
    	return i * m + j;
    };

    DSU d(n * m);
    for (int i = 0; i < n; ++ i) {
    	for (int j = 0; j < m; ++ j) {
    		if (s[i][j] == '.') {
    			for (int l = 0; l < 4; ++ l) {
    				int x = i + dx[l], y = j + dy[l];
    				if (s[x][y] == '.') {
    					d.merge(get(i, j), get(x, y));
    				}
    			}
    		}
    	}
    }

    std::vector<int> cnt(n * m);
    for (int i = 0; i < n; ++ i) {
    	for (int j = 0; j < m; ++ j) {
    		if (s[i][j] == '.') {
    			for (int l = 0; l < 4; ++ l) {
    				int x = i + dx[l], y = j + dy[l];
    				if (s[x][y] == '*') {
    					cnt[d.find(get(i, j))] ++ ;
    				}
    			}
    		}
    	}
    }

    for (int i = 0; i < k; ++ i) {
    	int x, y;
    	std::cin >> x >> y;
    	-- x, -- y;
    	std::cout << cnt[d.find(get(x, y))] << "\n";
    }
}

E. Chocolate Bar

题意:有n×m的方块,你每次可以横着切开分开两块,或者竖着切开分成两块,代价为切开长度的平方。你需要凑正好面积为k的方块,问最小代价。

记忆化搜索。每次枚举横着切和竖着切的位置,递归求最小值。

点击查看代码
int f[31][31][51];

void solve() {
    int n, m, k;
    std::cin >> n >> m >> k;
    auto dfs = [&](auto self, int n, int m, int k) -> int {
    	if (n * m == k || k == 0) {
    		return 0;
    	}

    	if (f[n][m][k] != -1) {
    		return f[n][m][k];
    	}

    	int res = 2e9;
    	for (int i = 1; i < n; ++ i) {
    		for (int x = 0; x <= i * m && x <= k; ++ x) {
    			if (k - x <= (n - i) * m) {
	    			res = std::min(res, m * m + self(self, i, m, x) + self(self, n - i, m, k - x));
    			}
    		}
    	}

    	for (int j = 1; j < m; ++ j) {
    		for (int x = 0; x <= n * j && x <= k; ++ x) {
    			if (k - x <= n * (m - j)) {
	    			res = std::min(res, n * n + self(self, n, j, x) + self(self, n, m - j, k - x));
    			}
    		}
    	}

    	return f[n][m][k] = res;
    };

    std::cout << dfs(dfs, n, m, k) << "\n";
}

F. Cut Length

暂时不会,等后面专攻计算几何再回来补。

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