D . 鲁道夫和球赛 D.鲁道夫和球赛 D.鲁道夫和球赛 每次测试时限: 2 秒 每次测试时限:2 秒 每次测试时限:2秒 每次测试的内存限制: 256 兆字节 每次测试的内存限制:256 兆字节 每次测试的内存限制:256兆字节
题目描述
鲁道夫和伯纳德决定和朋友们玩一个游戏。 n n n 人站成一圈,开始互相扔球。他们按顺时针顺序从 1 1 1 到 n n n 依次编号。
让我们把球从一个人向他的邻居移动称为一次过渡。转换可以顺时针或逆时针进行。
我们把从棋手 y 1 y_1 y1 到棋手 y 2 y_2 y2 的顺时针(逆时针)距离称为从棋手 y 1 y_1 y1 到棋手 y 2 y_2 y2 所需的顺时针(逆时针)转换次数。例如,如果是 n = 7 n=7 n=7 ,那么从 2 2 2 到 5 5 5 的顺时针距离是 3 3 3 ,而从 2 2 2 到 5 5 5 的逆时针距离是 4 4 4 。
初始时,球在编号为 x x x 的棋手处(棋手按顺时针方向编号)。在第 i i i 步时,持球人将球抛向 r i r_i ri ( 1 ≤ r i ≤ n − 1 1 \le r_i \le n - 1 1≤ri≤n−1 )顺时针或 7 7 7 ( 2 2 2 )逆时针的距离。( 1 ≤ r i ≤ n − 1 1 \le r_i \le n - 1 1≤ri≤n−1 ) 的距离顺时针或逆时针抛出。例如,如果有 7 7 7 名球员,第 2 2 2 名球员在接球后将球投掷到 5 5 5 处,那么球将被第 7 7 7 名球员(顺时针投掷)或第 4 4 4 名球员(逆时针投掷)接住。该示例的图示如下。
由于下雨,比赛在 m m m 次投掷后中断。雨停后,大家又聚在一起继续比赛。但是,没有人记得球在谁手里。结果,伯纳德记住了每次投掷的距离和****次投掷的方向(顺时针或逆时针)。
鲁道夫请你帮助他,根据伯纳德提供的信息,计算出 m m m 次抛球后可能拿到球的球员人数。
输入
输入的第一行包含一个整数 t t t ( 1 ≤ t ≤ 1 0 4 1 \le t \le 10^4 1≤t≤104 ) - 测试用例的数量。然后是测试用例的说明。
每个测试用例的第一行都包含三个整数 n , m , x n, m, x n,m,x ( 2 ≤ n ≤ 1000 2 \le n \le 1000 2≤n≤1000 , 1 ≤ m ≤ 1000 1 \le m \le 1000 1≤m≤1000 , 1 ≤ x ≤ n 1 \le x \le n 1≤x≤n ) - 分别是球员人数、投球次数和最先投球球员的号码。
接下来的 m m m 行按顺序包含每次投掷的信息。每一行都包含一个整数 r i r_i ri ( 1 ≤ r i ≤ n − 1 1 \le r_i \le n - 1 1≤ri≤n−1 )–距离。( 1 ≤ r i ≤ n − 1 1 \le r_i \le n - 1 1≤ri≤n−1 )–进行 i i i 次抛球的距离,以及一个符号 c i c_i ci ,等于 “0”、"1 “或”?
- 如果 c i c_i ci =‘0’,那么 i i i 次投掷是顺时针进行的、
- 如果 c i c_i ci =‘1’,那么 i i i 次投掷是逆时针方向、
- 如果 c i c_i ci =‘?’,那么伯纳德不记得方向, i i i 次投掷可能是顺时针,也可能是逆时针。
可以保证总和 n ⋅ m n \cdot m n⋅m ( n n n 乘以 m m m )是顺时针或逆时针。 n n n 乘以 m m m )不超过 2 ⋅ 1 0 5 2 \cdot 10^5 2⋅105 。
输出
每个测试用例输出两行。
第一行,输出游戏结束时可能拥有球的玩家 k k k ( 1 ≤ k ≤ n 1 \le k \le n 1≤k≤n ) 的数量。
下一行输出 k k k 、 b i b_i bi ( 1 ≤ b i ≤ n 1 \le b_i \le n 1≤bi≤n )–按递增顺序排列的球员号码。所有数字必须不同。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int N = 100010;
int main()
{
int t; cin>>t;
while(t--)
{
int n,m,x; scanf("%d%d%d",&n,&m,&x);
vector<int>ans(n); ans[x-1]=1;
while (m--)
{
int dis; char sign;
scanf("%d %c",&dis,&sign);
vector<int>temp(n);
if(sign=='0')
{
for(int i=0;i<n;i++)
if(ans[i]==1)
temp[(i+dis)%n]=1;
}
else if(sign=='1')
{
for(int i=0;i<n;i++)
if(ans[i]==1)
temp[(i-dis+n)%n]=1;
}
else
{
for(int i=0;i<n;i++)
if(ans[i]==1)
{
temp[(i+dis)%n]=1;
temp[(i-dis+n)%n]=1;
}
}
ans=temp;
}
int num=0;
for(int i:ans)
if(i==1)
num++;
cout<<num<<endl;
for(int i=0;i<n;i++)
if(ans[i]==1)
cout<<i+1<<" ";
cout<<endl;
}
return 0;
}
解题技巧:
一层层的递推就可以了,属于简单DP。
小技巧:
可以将每个球员的下标从
[
1
,
n
]
[1,n]
[1,n] 改变为
[
0
,
n
−
1
]
[0,n-1]
[0,n−1] ,这样就可以不用对一些情况进行特判 ,
当顺时针
进行传球时用(i+dis)%n
进行映射,
当逆时针
进行传球时用(i-dis+n)%n
进行映射。