8. 【Codeforces Round 933 (Div. 3)】 D.鲁道夫和球赛

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 1rin1 )顺时针或 7 7 7 2 2 2 )逆时针的距离。( 1 ≤ r i ≤ n − 1 1 \le r_i \le n - 1 1rin1 ) 的距离顺时针或逆时针抛出。例如,如果有 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 1t104 ) - 测试用例的数量。然后是测试用例的说明。

每个测试用例的第一行都包含三个整数 n , m , x n, m, x n,m,x ( 2 ≤ n ≤ 1000 2 \le n \le 1000 2n1000 , 1 ≤ m ≤ 1000 1 \le m \le 1000 1m1000 , 1 ≤ x ≤ n 1 \le x \le n 1xn ) - 分别是球员人数、投球次数和最先投球球员的号码。

接下来的 m m m 行按顺序包含每次投掷的信息。每一行都包含一个整数 r i r_i ri 1 ≤ r i ≤ n − 1 1 \le r_i \le n - 1 1rin1 )–距离。( 1 ≤ r i ≤ n − 1 1 \le r_i \le n - 1 1rin1 )–进行 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 nm n n n 乘以 m m m )是顺时针或逆时针。 n n n 乘以 m m m )不超过 2 ⋅ 1 0 5 2 \cdot 10^5 2105


输出

每个测试用例输出两行。

第一行,输出游戏结束时可能拥有球的玩家 k k k ( 1 ≤ k ≤ n 1 \le k \le n 1kn ) 的数量。

下一行输出 k k k b i b_i bi 1 ≤ b i ≤ n 1 \le b_i \le n 1bin )–按递增顺序排列的球员号码。所有数字必须不同。


代码:

#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,n1] ,这样就可以不用对一些情况进行特判
顺时针进行传球时用(i+dis)%n进行映射,
逆时针进行传球时用(i-dis+n)%n进行映射。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

古葬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值