Codeforces #639(div2) [C. Hilbert’s Hotel]

原题链接:https://codeforces.com/contest/1345/problem/C

题意

有无限个房间和无限位客人,最初每位客人都有一个房间.

给你一个长度为n的数组:{a0,a1,a3,…,an-2,an-1},然后对于任意整数k,房间k的客人被转移至房间k+ak mod n.

在转移过程后,如果每间房间仍然都只有一位客人,输出YES.

相对的,如果出现空房即出现房间有多位客人,输出NO.

输入

输入一个t(1<=t<=104),代表t组数据.

每组数据第一行有一个n(1<=n<=2·105),代表数组的长度.

数据第二行有n个整数,a0,a1,a3,…,an-2,an-1(-109<=ai<=109).

保证所有n的和不超过2·105.

输出

每组输出占一行,输出内容YESorNO.

示例

输入:

6

1

14

2

1 -1

4

5 5 5 1

3

3 2 1

2

0 1

5

-239 -2 -100 -3 -11

输出:

YES

YES

YES

NO

NO

YES

思路

题意中声明,房间k的客人被转移至房间k+ak mod n.

  • k可以分解成in与一个0n-1的数的和.

  • k=n*i+xi为任意整数,x0n-1内的任意数,所以k%n(n*i+x)%n,即x;ak mod n即ax.

由上述可得:n·i+x号房间的客人转移至n·i+x+ax号房间,所以两个相距n号房间的客人,转移的方向和增减的房号都是相同的.

示例中第三组数据为例,n=4,a[4]={5,5,5,1}.k%4后为123的客人向左走5k%4=0的客人向左走1.所以每个客人都会走到独一无二房间.

综上所述,对于每组数据,只要处理一组房间的情况,即n个房间.若有两间房间的客人走到同一间房间,则为NO,否则为YES.

由于ai取值范围为(-109<=ai<=109),所以在处理ai时对所有ai%n后加上n保证为正数.

对负数ai的处理

原本对于k+ak mod n的处理不是很正确,原本想到对于负数要向左偏移n,所以有了以下代码:

        scanf("%d", &n);
        for (int i = 0; i < n; i++)
        {                                   //各个ai都在录入时处理
            scanf("%d", &m);                //所以只要定义一个int类m储存当前ai
            int l = (m % n + i) % n + n;    //l为客人转移后的房间下标,m为ai,i为模后的x 
            if (book[l])                    //如果该房间已经有人住了,则该房间要住两位及以上的客人
                ans = false;                //答案为NO
            else
                book[l] = true;             //若没人住则住进去
        }

交后却不明不白WA了

后看到学长题解:
Codeforces #639(div2) [C. Hilbert’s Hotel]_第1张图片

本还很疑惑,自己试了试确实是这样:

Codeforces #639(div2) [C. Hilbert’s Hotel]_第2张图片

正是由于c++对于负数取模后依然是负数,两个算法的结果不一样.(还好这次碰见了,不然以后还要踩进什么大坑)

最后贴出我滴AC代码:

code

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define s(a, n) memset(a, n, sizeof(a))
#define g(a, max) fgets(a, max, stdin)
#define debug(a) cout << '#' << a << '#' << endl
using namespace std;
const unsigned long long MOD = 1e9 + 7;

int main()
{
    int t;
    bool book[200005];                      //用于标记该房间是否有人
    int m;
    bool fi = true;
    scanf("%d", &t);
    while (t--)
    {
        int n;
        s(book, false);                     //所有房间的客人正在转移
        bool ans = true;                    //答案默认为YES
        scanf("%d", &n);
        for (int i = 0; i < n; i++)
        {                                   //各个ai都在录入时处理
            scanf("%d", &m);                //所以只要定义一个int类m储存当前ai
            int l = (m % n + i + n) % n;    //l为客人转移后的房间下标,m为ai,i为模后的x 
            if (book[l])                    //如果该房间已经有人住了,则该房间要住两位及以上的客人
                ans = false;                //答案为NO
            else
                book[l] = true;             //若没人住则住进去
        }
        if (ans)
        {
            if (fi)
            {
                fi = !fi;
                printf("YES");
            }
            else
                printf("\nYES");
        }
        else
        {
            if (fi)
            {
                fi = !fi;
                printf("NO");
            }
            else
                printf("\nNO");
        }
    }
}

你可能感兴趣的:(cf题解)