将x[i]数组差分,此题变为挑选两个数,分别加a或b、减a或b。
为了方便,先将a、b与每个x[i]都除以gcd(a,b),如果不能整除则无解。
然后exgcd,找出a*u[i]+b*v[i]=x[i],然后对这个数加u[i]个a,v[i]个b就好辣!
选择任意一组解记为u0[i],v0[i]
则u[i]=u0[i]+k*b,v[i]=v0[i]-k*a
则u[i]=u0[i]+k*b,v[i]=v0[i]-k*a
使答案最优,要让每个|u[i]|+|v[i]|尽量小,即|u0[i]+k*b|+|v0[i]-k*a|,记为ans[i]
发现这是两个关于k的绝对值一次函数的和,必为单谷函数,因此三分求出使其最小的k值。
但是这样的解不一定合法,即满足∑u[i]=∑v[i]=0
因此我们需要调整k的值使其合法。注意到a*∑u[i]+b*∑v[i]=∑x[i]=0(差分的性质)
因此只要调整∑u[i]=0就好了。
即∑(u0[i]+k*b)=0。所以要将∑k调小(∑u[i])/b
把k减小1后的Δans[i]压进一个小根堆里,每次取堆顶更新。
然后就得到了最优的u[]和v[],答案即为(∑u[i]+∑v[i])/2。
注意a==b时要特判!
别问为什么,因为我就卡这里了!
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(i=j;i<=k;++i)
#define per(i,j,k) for(i=j;i>=k;--i)
#define sqr(x) ((x)*(x))
#define G getchar()
#define LL long long
#define pll pair<LL,LL>
#define mkp make_pair
#define X first
#define Y second
#define N 100005
#define inf 1000000001LL
LL n,d[N],A,B,U[N],V[N],K[N],ans;
priority_queue<pll,vector<pll>,greater<pll> >pq;
LL read(){
LL x=0;char ch=G;bool flg=0;
for(;ch<48||ch>57;ch=G)flg|=ch==45;
for(;ch>47&&ch<58;ch=G)x=x*10+ch-48;
return flg?-x:x;
}
void exgcd(LL a,LL b,LL&z,LL&x,LL&y){
if(!b){z=a;x=1;y=0;return;}
exgcd(b,a%b,z,y,x);y-=a/b*x;
}
LL get(LL u,LL v,LL k){
return abs(u+k*B)+abs(v-k*A);
}
LL Find(LL u,LL v,LL l,LL r){
if(r-l<3){
LL x=get(u,v,l),y=get(u,v,l+1),z=get(u,v,r);
if(y<x)++l,x=y;if(z<x)l=r;return l;
}
LL ml=l+(r-l)/3,mr=r-(r-l)/3;
if(get(u,v,ml)<get(u,v,mr))return Find(u,v,l,mr);
else return Find(u,v,ml,r);
}
int main(){
LL i,x,y,z,m=0;
n=read();A=read();B=read();
rep(i,1,n)d[i]=read();
per(i,++n,2)d[i]-=d[i-1];
exgcd(A,B,z,x,y);
if(z<0)z=-z,x=-x,y=-y;A/=z;B/=z;
rep(i,1,n){
if(d[i]%z){puts("-1");return 0;}
d[i]/=z;K[i]=Find(U[i]=x*d[i],V[i]=y*d[i],-inf,inf);
m+=U[i]+B*K[i];
}
if(A==B){
rep(i,1,n)ans+=abs(d[i]);
printf("%d\n",ans>>1);return 0;
}
if(m>0){
rep(i,1,n)pq.push(mkp(get(U[i],V[i],K[i]-1)-get(U[i],V[i],K[i]),i));
for(m/=B;m--;){
y=pq.top().Y;pq.pop();--K[y];
pq.push(mkp(get(U[i],V[i],K[i]-1)-get(U[i],V[i],K[i]),i));
}
}
else if(m<0){
rep(i,1,n)pq.push(mkp(get(U[i],V[i],K[i]+1)-get(U[i],V[i],K[i]),i));
for(m/=B;m++;){
y=pq.top().Y;pq.pop();++K[y];
pq.push(mkp(get(U[i],V[i],K[i]+1)-get(U[i],V[i],K[i]),i));
}
}
rep(i,1,n)ans+=abs(U[i]+K[i]*B)+abs(V[i]-K[i]*A);
printf("%lld\n",ans>>1);
return 0;
}