Problem Description
There are
n
soda sitting around a round table. soda are numbered from
1
to
n
and
i
-th soda is adjacent to
(i+1)
-th soda,
1
-st soda is adjacent to
n
-th soda.
Each soda has some candies in their hand. And they want to make the number of candies the same by doing some taking and giving operations. More specifically, every two adjacent soda x and y can do one of the following operations only once:
1. x -th soda gives y -th soda a candy if he has one;
2. y -th soda gives x -th soda a candy if he has one;
3. they just do nothing.
Now you are to determine whether it is possible and give a sequence of operations.
Each soda has some candies in their hand. And they want to make the number of candies the same by doing some taking and giving operations. More specifically, every two adjacent soda x and y can do one of the following operations only once:
1. x -th soda gives y -th soda a candy if he has one;
2. y -th soda gives x -th soda a candy if he has one;
3. they just do nothing.
Now you are to determine whether it is possible and give a sequence of operations.
题目大意:N个人围成一圈,每个人可以给左边或右边最多1个糖果,相邻两个人最多有一次糖果的传递(a给b一个,b不能再给a)
思路:N个人中最多的一定会向外给(除非所有人一样多),假如他给了左边一个,那么左边的那个人就只能和再左的人给/拿糖果,进行操作之后如果和最后的平均数不一致,那么这个这种方式错误,再令第一个人给右边一个,然后进行相同的操作。这样对数组按顺时针和逆时针分辨判断一次即可。
可能有这种特例,按第一个顺序处理时,某个人可能和他左边的人没有操作,那么说明这个人的糖果数 = 平均值,下一个人也就不可能和他再进行操作,所以操作的方向不会改变。
注意计算平均值时考虑不能整除的情况。
#include<cstdio>
using namespace std;
const int SIZE = 100005;
int a1[SIZE];
int a2[SIZE];
int N,ave;
int ans[SIZE][2];
int no = 0;
int left(int p){
p--;
if(p < 0) p = N - 1;
return p;
}
int right(int p){
p++;
return p % N;
}
int main() {
// TODO Auto-generated method stub
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&N);
long long sum = 0;
int max = -1;
int pos = 0;
for(int i=0;i<N;i++){
scanf("%d",&a1[i]);
a2[i] = a1[i];
if(a1[i] > max){
max = a1[i];
pos = i;
}
sum += a1[i];
}
long long ln = N;
if(sum%ln != 0){
printf("NO\n");
continue;
}
ave = (int)(sum / ln);
if(a1[pos] - ave > 2 || a1[pos] - ave < -2){
printf("NO\n");
continue;
}
bool flag = true;
no = 0;
int p = pos, next = left(p);
for(int i=1;i<=N;i++){
if(a1[p] > ave){
a1[p]--;
a1[next]++;
ans[no][0] = p + 1;
ans[no++][1] = next + 1;
}
else if(a1[p] < ave){
a1[p]++;
a1[next]--;
if(a1[next]<0){
flag = false;
break;
}
ans[no][0] = next + 1;
ans[no++][1] = p + 1;
}
if(i>1 && a1[p]!=ave){
flag = false;
break;
}
p = next;
next = left(next);
}
if(flag){
printf("YES\n");
printf("%d\n",no);
if(no != 0){
for(int i=0;i<no;i++) printf("%d %d\n",ans[i][0],ans[i][1]);;
}
continue;
}
flag = true;
no = 0;
p = pos;
next = right(p);
for(int i=1;i<=N;i++){
if(a2[p] > ave){
a2[p]--;
a2[next]++;
ans[no][0] = p + 1;
ans[no++][1] = next + 1;
}
else if(a2[p] < ave){
a2[p]++;
a2[next]--;
if(a2[next]<0){
flag = false;
break;
}
ans[no][0] = next + 1;
ans[no++][1] = p + 1;
}
if(i>1 && a2[p]!=ave){
flag = false;
break;
}
p = next;
next = right(next);
}
if(flag){
printf("YES\n");
printf("%d\n",no);
if(no != 0){
for(int i=0;i<no;i++) printf("%d %d\n",ans[i][0],ans[i][1]);;
}
}
else{
printf("NO\n");
}
}
}