Error Swap_arc198c分析与解答
C - Error Swap
操作在交换的基础上增加了加减1,首先可以发现,操作前后数组的所有数的和不变,因此如果初始时a数组元素的和不等于b数组元素的和,则a不可能变成b。
其实只要a数组元素的和等于b数组元素的和,a就一定能变成b,(其实还需要n>2,因为需要进行交换操作,请往下看),因为当对a_i和a_j (i<j)先交换再进行一次操作,可以让a_i减少1,让a_j增加1,若i>j,则先进行一次操作再交换,就也可以让a_i减少1,a_j增加1,而a数组元素的和与b数组元素的和相等的话,a中元素需要减少的量和需要增加的量是相等的,不断选出a_i和a_j,其中a_i是需要减小的元素,a_j是需要增大的元素,进行对a_i+1,对a_j-1的操作最终就可以让a_i等于b_i让a_j等于b_j。
但交换的操作如何实现呢?先看看有两个元素的情况,如果n=2,那么
a1,a2只能变成a2-1,a1+1,因为再变就又回到a1,a2,是无法实现交换操作的。n=2的情况我们特判。
n>2时,如果要交换a_i和a_j (i<j),可以借助第三个元素完成,如果i>1,可以借助他们左边的元素a_1完成:
用(a,b)(a<b)表示对a位置和b位置上的元素进行操作。
依次进行操作:(1,i) (1,j) (1,i)
如果i>1不满足,其实借助这两个元素右边的元素a_n也可以:
依次操作:(i,n) (j,n) (i,n)
如果i=1并且j=n,那能不能借助两个元素中间的元素对i,j进行交换?答案是可以,但是相较于以上两种交换的操作方式,这种交换的操作方式可能不那么直接想到,需要构造,可以按如下思路:
用a_i和a_j之间的a_p进行中转,i<p<j,最后一次操作对位置i,j进行,也就是最后一次操作是(i,j),那么最后一次操作前,i 位置上的值应该是a_i-1,j 位置上的值应该是a_j+1,如果将a_i向右换一次,向左换两次,就得到值a_i-1,同样将a_j向左换一次,向右换两次,得到值a_j+1,这一过程可以这样完成:
(i,j) (i,p) (p,j) (i,p)
加上最后的(i,j)的话,用p为中转交换(i,j)的操作序列是:
(i,j) (i,p) (p,j) (i,p) (i,j)
当i=1,j=n时,可以用2作为中转,写成:
(1,n) (1,2) (2,n) (1,2) (1,n)
现在分析一下总共需要的操作次数,让每个a_i和b_i的差值(差的绝对值)都最大,则总差值为nm,则需要进行mn/2次的a_i->a_i-1,a_j->a_j+1(记作“改变值”),如果让这mn/2次的改编自中,有尽量多的i=1和j=n,这样最后的总操作数会更大,那么在这mn/2次改变值中,最多有m/2次是对1和n改变值,所以总操作次数为:
mn/2*(交换需要3次+操作的1次)+(mn/2-m/2)*(交换需要5次+操作的1次),小于题目要求的31000。
#include<bits/stdc++.h>
using namespace std;
using ll=long long;const ll maxn=100+5;
ll n;
ll a[maxn],b[maxn];
vector<pair<ll,ll>> op;void opt(ll x,ll y){if(x>y) swap(x,y);op.push_back({x,y});ll t=a[x];a[x]=a[y]-1;a[y]=t+1;
}void swp(ll x,ll y){if(y<x) swap(x,y);if(x>1) {opt(1,x);opt(1,y);opt(1,x);}else if(y<n){opt(n,x);opt(n,y);opt(n,x);}else {opt(1,n);opt(1,2);opt(2,n);opt(1,2);opt(1,n);}
}int main()
{ios::sync_with_stdio(0);cin.tie(0);cin>>n;ll s1=0,s2=0;for(ll i=1;i<=n;i++) {cin>>a[i];s1+=a[i];}for(ll i=1;i<=n;i++) {cin>>b[i];s2+=b[i];}if(n==2){if(a[1]==b[1] && a[2]==b[2]) {cout<<"Yes"<<"\n";cout<<0<<"\n";}else if(a[2]-1==b[1] && a[1]+1==b[2]){cout<<"Yes"<<"\n";cout<<1<<"\n";cout<<1<<" "<<2<<"\n";}else {cout<<"No"<<"\n";}}else {if(s1!=s2) {cout<<"No"<<"\n";}else {cout<<"Yes"<<"\n";op.clear();vector<ll> p,q;for(ll i=1;i<=n;i++){ll d=a[i]-b[i];if(d>0) {for(ll j=1;j<=d;j++) p.push_back(i);}else if(d<0){d=-d;for(ll j=1;j<=d;j++) q.push_back(i);}}//printf("p大小:%lld q大小:%lld\n",p.size(),q.size());for(ll i=0;i<p.size();i++){ll x=p[i],y=q[i];if(x<y) {swp(x,y);opt(x,y);}else {opt(x,y);swp(x,y);}}/*printf("Seq after operations:\n");for(ll i=1;i<=n;i++) cout<<a[i]<<" ";cout<<"\n";*/cout<<(ll)op.size()<<"\n";for(ll i=0;i<op.size();i++){cout<<op[i].first<<" "<<op[i].second<<"\n";}}}return 0;
}