VP Toyota Programming Contest 2024#12(AtCoder Beginner Contest 384)

A - aaaadaa

题意:给你一个字符串和两个字符c1,c2,把字符串里的所有不等于c1的字符都换成c2

模拟即可。

点击查看代码
void solve() {
    int n;
    char a, b;
    std::cin >> n >> a >> b;
    std::string s;
    std::cin >> s;
    for (auto & c : s) {
    	if (c != a) {
    		c = b;
    	}
    }

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

B - ARC Division

题意:你有一个初始分,按顺序参加比赛,比赛由两种,有不同的计分范围,如果你的分数在这个比赛的计分范围内,就会加上ai,求最后分数。

也是模拟。

点击查看代码
void solve() {
    int n, ans;
    std::cin >> n >> ans;
    for (int i = 0; i < n; ++ i) {
    	int d, a;
    	std::cin >> d >> a;
    	if (d == 1 && ans >= 1600 && ans <= 2799) {
    		ans += a;
    	} else if (d == 2 && ans >= 1200 && ans <= 2399) {
    		ans += a;
    	}
    }
    std::cout << ans << "\n";
}

C - Perfect 排名表

题意:有五个题目,每个题目有一个分数,你要求出做出这五题其中一些题的所有排列的分数,然后按分数从大到小输出,如果分数相同那就字典序小的输出。

dfs搜出所有排列,然后排序。

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

    std::vector<std::pair<std::string, int> > ans;
    auto dfs = [&](auto self, int u, std::string s, int val) -> void {
    	if (u == 5) {
    		if (s.size()) {
    			ans.push_back({s, val});
    		}
    		return;
    	}

    	self(self, u + 1, s, val);
    	s += 'A' + u;
    	val += a[u];
    	self(self, u + 1, s, val);
    };

    dfs(dfs, 0, "", 0);
    std::sort(ans.begin(), ans.end(), [&](std::pair<std::string, int> & a, std::pair<std::string, int> & b) {
    	if (a.second == b.second) {
    		return a.first < b.first;
    	}
    	return a.second > b.second;
    });

    for (auto & [s, v] : ans) {
    	std::cout << s << "\n";
    }
}

D - Repeated Sequence
题意:有一个无限长的序列,以n为周期,现在给你一个周期里的数,求这个序列有没有一段连续区间的和等于s。

记sum等于一个周期的和,如果s <= sum, 我们延长一倍数组双指针模拟就行。如果s > sum,我们选的区间应该是一些完整周期加上结尾一些数和开头一些数,那么我们把所有前缀和记录起来,从后枚举后缀和,已知当前后缀和为x, 那么我们要求一个前缀y, 使得 (s - x - y) % sum = 0,因为y一定小于sum,那么也就是 y = (s - x) % sum。

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

    std::set<i64> set;
    i64 sum = 0;
    for (int i = 0; i < n; ++ i) {
    	sum += a[i];
    	set.insert(sum);
    }

    if (sum >= s) {
		i64 sum = 0;
    	for (int i = 0, j = 0; i < n; ++ i) {
    		j = std::max(j, i);
    		while (j < 2 * n && sum < s) {
    			sum += a[j % n];
    			++ j;
    		}

    		if (sum == s) {
    			std::cout << "Yes\n";
    			return;
    		}

    		sum -= a[i];
    	}
    	std::cout << "No\n";
    	return;
    }

    set.insert(0);

    i64 x = 0;;
    for (int i = n - 1; i >= 0 && x <= s; -- i) {
    	x += a[i];
    	if (set.count((s - x) % sum)) {
    		std::cout << "Yes\n";
    		return;
    	}
    }

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

E - Takahashi is Slime 2

题意:一个矩阵,你有一个初始点,你可以往你相邻的点扩展,如果这个点 <= 你的值 / x,那么你可以吃它,并且占领它的格子。问你最大的值是多少。

我们把所有可以吃的格子用小根堆维护起来,每次吃最小的格子然后把它的邻格入队。如果连最小的都吃不了,就只能退出。

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

    const int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
    using A = std::array<i64, 3>;
    std::priority_queue<A, std::vector<A>, std::greater<A> > heap;

    std::vector st(n, std::vector<int>(m));
    st[sx][sy] = 1;
    i64 ans = a[sx][sy];
    for (int i = 0; i < 4; ++ i) {
    	int nx = sx + dx[i], ny = sy + dy[i];
    	if (nx < 0 || nx >= n || ny < 0 || ny >= m) {
    		continue;
    	}

    	st[nx][ny] = 1;
    	heap.push({a[nx][ny], nx, ny});
    }

    while (heap.size()) {
    	auto [val, x, y] = heap.top(); heap.pop();
    	if ((__int128)val * X >= ans) {
    		break;
    	}

    	ans += val;
    	for (int i = 0; i < 4; ++ i) {
    		int nx = x + dx[i], ny = y + dy[i];
    		if (nx < 0 || nx >= n || ny < 0 || ny >= m || st[nx][ny]) {
    			continue;
    		}

    		st[nx][ny] = 1;
    		heap.push({a[nx][ny], nx, ny});
    	}
    }

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

F - Double Sum 2

题意:如果x二进制下末尾有k个0,那么F(x) = x >> k, 给你一个数组求i=1nj=inf(ai + aj)。

这题直接求貌似很难,我们可以按位考虑,对于一个k,有多少ai + aj 二进制下末尾有至少k个0?我们以f[k] 表示 二进制下末尾至少k个零的ai + aj 总和。那么第k位的贡献位f[k] - f[k+1] >> k。之所以要减去f[k+1],因为我们算的是至少k个零,但我们应该求正好k的零的总和,所以利用差分思想可以得到正好k个零的总和。
怎么算有多少和至少末尾有k个零?我们设x = (1 << k) - 1,那么ai需要加上末尾k位的数y为x & (x + 1 - (ai & x))的数,我们可以用个桶统计末尾k位为i的元素和以及元素个数, 记为sum和cnt,那么和ai相加至少有k个零的数和aif[k]的贡献为sum[y] + cnt[y] * a[i]

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

	auto get = [&](int x, int y) -> int {
		return x & (x + 1 - (x & y));
	};

	const int N = 1 << 24;
	std::vector<i64> sum(N), cnt(N);
	std::vector<i64> f(26);
	i64 ans = 0;
	for(int k = 24; k >= 0; -- k) {
		int x = (1 << k) - 1;
		for (int i = n - 1; i >= 0; -- i) {
			sum[a[i] & x] += a[i]; cnt[a[i] & x] += 1;
			f[k] += sum[get(x, a[i])] + cnt[get(x, a[i])] * a[i];
		}

		for (int i = 0; i < n; ++ i) {
			sum[a[i] & x] = 0;
			cnt[a[i] & x] = 0;
		}

		ans += f[k] - f[k + 1] >> (i64)k;
	}

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