CF1276E Four Stones
首先判断是否无解:
如果初始四颗石头都在一个位置上需要直接特判掉。
令 \(g=\gcd(a_2-a_1,a_3-a_1,a_4-a_1),g2=\gcd(b_2-b_1,b_3-b_1,b_4-b_1)\) ,那么需要有 \(g=g_2\) 并且 \(a_1=b_1 \pmod g\) ,否则显然无解。
令 \(d=a_1\bmod g\)
为了方便,将所有坐标变 \(x\) 为 \(x=(x-d)/g\)。此时可以发现,在任何操作下,每个坐标的奇偶性都是不变的,因此 \(a\) 与 \(b\) 之间的奇数和偶数数量应该相同。否则仍然无解。
然后考虑固定两个中间状态:将 \(a_1,\ldots a_4\) 放到 \([x,x+1]\) 上,将 \(b_1,\ldots b_4\) 放到 \([y,y+1]\) 上,最后将 \([x,x+1]\) 上的石头放到 \([y,y+1]\) 上即可,输出时只要把 \(b_1,\ldots b_4\) 放到 \([y,y+1]\) 这一部分倒着输出即可。(为了方便这里的 \(x,y\) 统一为偶数)
接下来先考虑怎么把石头放到 \([x,x+1]\) 上。
令 \(\Delta=\) 任意两块石头之间的最大距离。
为了方便,假设 \(a\) 递增。
当其中一颗石头 \(a_i\) 在 \([a_1+\frac{\Delta}{4},a_1+\frac{3\Delta}{4}]\) 时,
考虑将 \([a_1,a_4]\) 分成 \([a_1,a_i]\) 和 \([a_i,a_4]\),并将所有的石头对称到相对于 \(a_i\) 较近的一半。
此时 \(a_i\) 将成为最左边或者最右边的石头,新的最大距离 \(\Delta'\) 最大为 \(\frac{3\Delta}{4}\),\(\Delta\) 减少至少 \(\frac{1}{4}\)。
否则假如不存在这颗石头时,令 \(d_i=\min(a_i-a_1,a_4-a_i)\) ,即从 \(a_i\) 到最近两端石头的最短距离,那么可以发现 \(d_2,d_3<\frac{\Delta}{4}\) 且至少有一个数 \(\neq 0\) 。否则此时已经有 \(g=1=\Delta\),已经完成目标。
然后观察进行 \((a_i,a_j),(a_i,a_k)\) 两次操作将 \(a_i\) 变为 \(a_i+2(a_k-a_j)\)。这样就可以将 \(d_i\) 变成 \(d_i+2d_j\)。在这样 \(\mathcal O(\log \Delta)\) 次操作后,会有 \(\max(d_2,d_3)\ge \frac{\Delta}{4}\),然后就可以继续重复上面的操作了。
最后,所有的 \(a_i\in [x,x+1]\)。为了方便,如果 \(x\) 是奇数,可以让所有的 \(a_i=x\) 变成 \(x+2\)。
总复杂度为 \(\mathcal O(\log \Delta)\) 的。
然后考虑怎么将 \([x,x+1]\) 上的石子移到 \([y,y+1]\) 上,假设此时要将它们移动 \(2d\),假设 \(2d\ge 0\)。
可以发现任何石头的排列的排列都可以通过将最右边那颗石头对称两次来移动 \(2\Delta\)。
假设 \(a\) 递增。
令一个叫 Expand 操作为 \((a_3,a_1),(a_2,a_4)\)。可以发现,如果使用 Expand \(k\) 次,最大距离 \(\Delta\) 将呈指数增长。
然后我们可以将石头移动 \(2d\) 如下:
- 进行 Expand 操作直到 \(\Delta >d\)。
- 当 \(\Delta \le d\) 时,进行上面那种操作将所有石头移动 \(2\Delta\),并将 \(d\) 减少 \(\Delta\)。
- 若 \(\Delta =1\),则退出。
- 执行 Expand 的逆操作,返回步骤 2
最后可以得到 \(\Delta =1,d=0\) 。此外由于 \(\Delta\) 在 Expand 操作中呈指数增长,对于每个 \(\Delta\) 基本操作都是 \(\mathcal O(1)\) 的,因此总操作次数是 \(\mathcal O(\log d)\) 的。
#include<bits/stdc++.h>
#define int long long
#define R(i,a,b) for(int i=(a),i##E=(b);i<=i##E;i++)
#define L(i,a,b) for(int i=(b),i##E=(a);i>=i##E;i--)
using namespace std;
int a[11],b[11],g,g2;
vector<pair<int,int> >ans1,ans2,ans;
inline void nos(int a=-1)
{
cout<<a<<endl;
exit(0);
}
inline int gcd(int a,int b)
{
return !b?a:gcd(b,a%b);
}
void solve(int *a,vector<pair<int,int> >&ans)
{
while(1)
{
sort(a+1,a+5);
if(a[4]-a[1]==1) break;
int p=1e10;
while(1)
{
int l=a[1]*3+a[4],r=a[1]+a[4]*3;
if(l<=a[2]*4&&a[2]*4<=r) p=a[2];
if(l<=a[3]*4&&a[3]*4<=r) p=a[3];
if(p!=1e10) break;
int d2=min(a[2]-a[1],a[4]-a[2]),d3=min(a[3]-a[1],a[4]-a[3]);
if(d2>d3) swap(d2,d3),swap(a[2],a[3]);
int id1,id2;
if(a[4]-a[3]<a[3]-a[1]) id1=3,id2=4;
else id1=1,id2=3;
if(a[4]-a[2]<a[2]-a[1]) swap(id1,id2);
ans.emplace_back(a[2],a[id1]);
a[2]=(a[id1]<<1)-a[2];
ans.emplace_back(a[2],a[id2]);
a[2]=(a[id2]<<1)-a[2];
}
if(a[1]+a[4]>=(p<<1))
{
R(i,1,4) if(a[i]<p) ans.emplace_back(a[i],p),a[i]=(p<<1)-a[i];
}
else
{
R(i,1,4) if(a[i]>p) ans.emplace_back(a[i],p),a[i]=(p<<1)-a[i];
}
}
sort(a+1,a+5);
if(a[1]&1)
{
R(i,1,4) if(a[i]&1) ans.emplace_back(a[i],a[i]+1),a[i]+=2;
}
sort(a+1,a+5);
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(NULL);
cin>>a[1]>>a[2]>>a[3]>>a[4]>>b[1]>>b[2]>>b[3]>>b[4];
sort(a+1,a+4+1),sort(b+1,b+4+1);
R(i,2,4) g=gcd(g,a[i]-a[1]),g2=gcd(g2,b[i]-b[1]);
if(g^g2) nos();
if(!g) nos(a[1]==b[1]?0:-1);
if((a[1]-b[1])%g) nos();
int d=(a[1]%g+g)%g;
R(i,1,4) a[i]=(a[i]-d)/g,b[i]=(b[i]-d)/g;
solve(a,ans1),solve(b,ans2);
R(i,1,4) if((a[i]&1)!=(b[i]&1)) nos();
d=(b[1]-a[1])/2;
for(;3*(a[4]-a[1])<=abs(d);)
{
ans1.emplace_back(a[3],a[1]),a[3]=(a[1]<<1)-a[3];
ans1.emplace_back(a[2],a[4]);a[2]=(a[4]<<1)-a[2];
sort(a+1,a+5);
}
while(1)
{
while(abs(d)>=a[4]-a[1])
{
if(d<0)
{
d+=a[4]-a[1];
R(i,1,2)
{
R(j,2,4)
{
ans1.emplace_back(a[j],a[1]);
a[j]=(a[1]<<1)-a[j];
}
sort(a+1,a+5);
}
}
else
{
d-=a[4]-a[1];
R(i,1,2)
{
R(j,1,3)
{
ans1.emplace_back(a[j],a[4]);
a[j]=(a[4]<<1)-a[j];
}
sort(a+1,a+5);
}
}
}
if(a[4]-a[1]<=1) break;
ans1.emplace_back(a[1],a[2]);a[1]=(a[2]<<1)-a[1];
ans1.emplace_back(a[4],a[3]);a[4]=(a[3]<<1)-a[4];
sort(a+1,a+5);
}
reverse(ans2.begin(),ans2.end());
for(auto x:ans2) ans1.emplace_back((x.second<<1)-x.first,x.second);
for(auto x:ans1) if(x.first!=x.second) ans.emplace_back(x.first*g+d,x.second*g+d);
cout<<ans.size()<<endl;
for(auto x:ans) cout<<x.first<<" "<<x.second<<'\n';
}

浙公网安备 33010602011771号