AtCoder Regular Contest 159 C

https://atcoder.jp/contests/arc159/tasks/arc159_c

题解

当最终每个数都一样时,总和一定是 nn 的倍数。而每次操作都是给总和加上了 s=n(n+1)2s=\dfrac{n(n+1)}{2}。所以如果初始的总和 sumsumsum+ssum+s 都不是 nn 的倍数那么一定无解。

否则一定有解。考虑两次操作:(1,2,,n),(n,n1,,1)(1,2,\cdots,n),(n,n-1,\cdots,1),所有数的相对大小没有改变。但如果交换第二次的 nnn1n-1,就相当于是第一个数-1,第二个数+1,其它数不变。即,我们可以通过两次操作让一个数-1,同时让另一个数+1。

我们先将总和 sumsum 调整至 nn 的倍数,令 k=sumnk=\dfrac{sum}{n}。然后每次挑一个小于 kk 的+1,挑一个大于 kk 的-1,最终一定刚好全部等于 kk

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
int n,m,sum,a[55];
int ans[10005][55];
void modify(int x,int y)// x=x-1,y=y+1
{
m++;
ans[m][x]=1,ans[m][y]=2;
int cnt=3;
for(int i=1;i<=n;i++)
if(i!=x&&i!=y) ans[m][i]=cnt++;
m++;
ans[m][x]=n-1,ans[m][y]=n;
cnt=n-2;
for(int i=1;i<=n;i++)
if(i!=x&&i!=y) ans[m][i]=cnt--;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],sum+=a[i];
if(sum%n)
{
sum+=n*(n+1)/2;
for(int i=1;i<=n;i++) a[i]+=i;
m++;
for(int i=1;i<=n;i++) ans[m][i]=i;
}
if(sum%n) cout<<"No"<<'\n';
else
{
cout<<"Yes"<<'\n';
int k=sum/n;
queue<pii> q1,q2;
for(int i=1;i<=n;i++)
{
if(a[i]>k) q1.push({i,a[i]-k});
if(a[i]<k) q2.push({i,k-a[i]});
}
while(!q1.empty()&&!q2.empty())
{
if(q1.front().second==0) q1.pop();
if(q2.front().second==0) q2.pop();
if(q1.empty()&&q2.empty()) break;
modify(q1.front().first,q2.front().first);
q1.front().second--;
q2.front().second--;
}
cout<<m<<'\n';
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++) cout<<ans[i][j]<<" \n"[j==n];
}
return 0;
}

AtCoder Regular Contest 159 C
https://je3ter.github.io/2023/10/15/ACM/AtCoder Regular Contest 159 C/
作者
Je3ter
发布于
2023年10月15日
许可协议