[CF1941D] Rudolf and the Ball Game 的题解

题目大意

\(n\) 个人投球,投了 \(m\) 次。第 \(i\) 次投球时想左、右或者随便一个方向投掷 \(r_i\) 个人。从第 \(x\) 个人开始投球,询问最后球在最后有可能在谁的手里。

其中 \(1\le n,m \le 1000,1\le x,r\le n,\sum n\cdot m \le 2\times 10^5\)

思路

如果遇到方向不确定的情况,可以暴力的考虑直接枚举。考虑在最坏的情况下,全部的投球肯能方向不确定,那么我们就需要枚举 \(2^m\),因为这些人一共会接到 \(2^m\) 次球。

在一轮投球中只有 \(n\) 个人但是却接到了 \(2^m\) 次球,可见一个人可能会多次接到球。因为在一轮中,不论一个人接到多少次球那么效果其实都是一样的。

所以设 \(f_{i,j}\) 表示在第 \(i\) 次投球时,第 \(j\) 个人是否有可能拿到球。假设 \(g(j,r_i)\) 表示第 \(j\) 个人移动 \(r_i\) 后的位置,发么状态转移方程为

\[f_{i,g(j,r_i)}=\max(f_{i,g(j,r_i)},f_{i-1,j}) \]

AC Code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1005;
int n,m,a[N],f[N][N],x;
char c[N];
void solve(){
	cin>>n>>m>>x;
	for(int i=1;i<=m;i++) cin>>a[i]>>c[i];
	for(int i=0;i<=m;i++) for(int j=0;j<=n;j++) f[i][j]=0;
	f[0][x-1]=1;
	for(int i=1;i<=m;i++){
		for(int j=0;j<n;j++){
			if(c[i]=='0'||c[i]=='?') f[i][(j+a[i])%n]|=f[i-1][j];
			if(c[i]=='1'||c[i]=='?') f[i][(j-a[i]+n)%n]|=f[i-1][j];
		}
	}
	vector<int> ans;
	for(int i=0;i<n;i++) if(f[m][i]) ans.push_back(i+1);
	cout<<ans.size()<<'\n';
	for(int i:ans) cout<<i<<' ';
	cout<<'\n';
}signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T;cin>>T;
	while(T--) solve();
	return 0;
}
posted @ 2024-07-14 13:45  未抑郁的刘大狗  阅读(7)  评论(0编辑  收藏  举报