题意
有无限个房间和无限位客人,最初每位客人都有一个房间.
给你一个长度为
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.
输出
每组输出占一行,输出内容
YES
orNO
.
示例
输入:
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
可以分解成i
个n
与一个0
到n-1
的数的和. -
设
k=n*i+x
,i
为任意整数,x
为0
到n-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
后为1
,2
,3
的客人向左走5
,k%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了
后看到学长题解:
本还很疑惑,自己试了试确实是这样:
正是由于c++
对于负数取模后依然是负数,两个算法的结果不一样.(还好这次碰见了,不然以后还要踩进什么大坑)
最后贴出我滴AC代码:
code
#include <iostream>
#include <cstdio>
#include <stdlib.h>
#include <stack>
#include <queue>
#include <cmath>
#include <string.h>
#include <cstring>
#include <algorithm>
#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");
}
}
}