题意
N个人首尾相连,每个人可以给旁边的人一个SODA,也可以从旁边的人那里拿一个SODA。两个人之间给或拿只能操作一次,求是否存在操作方案,使得最后所有人SODA数目相同。
题解
模拟。第一个人可能从第二个人那里拿一个SODA,也可能给第二个人一个SODA,也可能不操作。模拟三种情况即可。
注意事项
需要注意某一个人的SODA初始数与平均值差2,依然有可能经过几次操作后,每个人的SODA数目相同。
代码
#include <iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
int num[
100010];
struct Node{
int from,to;
};
int s1[
100010],s2[
100010];
int u[
100010],v[
100010];
int k,n;
bool give(
int *nu){
int i=
2;
for(;i<=n;i++){
if(nu[i]==
1){
nu[i]--;
nu[i%n+
1]++;
u[k]=i;
v[k++]=i%n+
1;
}
else if(nu[i]==-
1){
nu[i]++;
nu[i%n+
1]--;
v[k]=i;
u[k++]=i%n+
1;
}
else if(nu[i]==
0){
continue;
}
else{
break;
}
}
if(i!=n+
1||nu[
1]){
return false;
}
return true;
}
void clear(){
memset(u,
0,
sizeof(u));
memset(v,
0,
sizeof(v));
k=
0;
}
int main()
{
int kase;
scanf(
"%d",&kase);
while(kase--){
scanf(
"%d",&n);
long long allSum=
0;
for(
int i=
1;i<=n;i++){
scanf(
"%d",&num[i]);
allSum+=num[i];
}
if(allSum%n!=
0){
printf(
"NO\n");
continue;
}
allSum/=n;
bool can=
true;
for(
int i=
1;i<=n;i++){
num[i]-=allSum;
s1[i]=s2[i]=num[i];
if(num[i]>
2||num[i]<-
2){
can=
false;
break;
}
}
if(!can){
puts(
"NO");
continue;
}
bool noMove=
true;
for(
int i=
1;i<=n;i++){
if(num[i]!=
0){
noMove=
false;
break;
}
}
if(noMove){
printf(
"YES\n0\n");
continue;
}
clear();
s1[
1]++;
s1[
2]--;
u[k]=
2;
v[k++]=
1;
if(!give(s1)){
can=
false;
}
if(!can){
clear();
s2[
1]--;
s2[
2]++;
v[k]=
2;
u[k++]=
1;
if(give(s2)){
can=
true;
}
else{
clear();
}
}
if(!can&&give(num)){
can=
true;
}
if(can){
puts(
"YES");
printf(
"%d\n",k);
for(
int i=
0;i<k;i++){
printf(
"%d %d\n",u[i],v[i]);
}
}
else{
puts(
"NO");
}
}
return 0;
}
转载请注明原文地址: https://ju.6miu.com/read-3043.html