3.22练习

原题链接:https://codeforces.com/contest/1941/problem/D
这道题vp的时候脑子瓦特了,没写出来,气死了喵~
题意是有n个man围成一个圈圈,编号从1到n顺时针排列最开始球在编号为x的小朋友手里。然后球会经过m次传递,每次传递都有要输入一个距离和方向(可能是顺时针、逆时针,或者不确定喵~)。最后,我们需要找出球可能落在哪些man手里。
所以这题可以用dp写,我们把每次传球看成一个状态,即顺时针,逆时针,或者两者均可,然后通过状态转移方程来判断最后哪些位置可以达到(一开始想的是把到一个问号前的转动数值和作为一个状态存储,结果发现想复杂了喵~~~)
对于每次传递,我们根据传递的距离r和方向c来更新球可能的位置。
如果方向是顺时针(c == '0'),球会从当前位置 j 传递到 (j + r) % n。
如果方向是逆时针(c == '1'),球会传递到 (j - r + n) % n(+n为了避免负数)。
如果方向不确定(c == '?'),球可能传递到 (j + r) % n 或 (j - r + n) % n。
代码如下

点击查看代码
#include <bits/stdc++.h>
#define i64 long long
using namespace std;
void solve(){
	int n, m, x;
	cin >> n >> m >> x;
	vector <vector <i64>> f (m + 1, vector <i64> (n + 1, 0));  
	f[0][x - 1] = 1;
	for(int i = 1; i <= m; i++){
		i64 b;
		char c;
		cin >> b >> c;
		for(int j = 0; j < n; j++){
			if(f[i - 1][j]){
				if(c == '0') f[i][(j + b) % n] = 1;
				else if(c == '1') f[i][(j - b + n) % n] = 1;
				else {
					f[i][(j - b + n) % n] = 1;
					f[i][(j + b) % n] = 1;
				}
			}
		}
	}
	vector <int> result;
	for(int i = 0; i < n; i++){
		if(f[m][i]) result.push_back(i);
	}
	cout << result.size() << endl;
	for(int i = 0; i < result.size(); i++) cout << result[i] + 1 << ' ';
	cout << endl;
}
int main()
{
	int t;
	cin >> t;
	while(t--){
		solve();
	}
}
posted @ 2025-03-21 23:55  扶风zer0  阅读(22)  评论(0)    收藏  举报