记录编号 361018 评测结果 AAAAAAAAAAAAAAAAAAAA
题目名称 修整数列 最终得分 100
用户昵称 GravatarFoolMike 是否通过 通过
代码语言 C++ 运行时间 0.410 s
提交时间 2017-01-02 17:27:27 内存使用 2.33 MiB
显示代码纯文本
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int N=1e5+10;
typedef long long ll;
int n,a,b,Gcd,c[N],p[N];
ll tx,ty,x[N],y[N];
int gcd(int x,int y){return y?gcd(y,x%y):x;}
void ex_gcd(ll a,ll b,ll &x,ll &y){
	if (!b){x=1;y=0;return;}
	ex_gcd(b,a%b,x,y);
	ll m=x;
	x=y;y=m-a/b*y;
}
void Min(ll &x,ll &y){//将|x+y|调整到最小,保持ax+by不变 
	ll x1=x,x2=x,y1=y,y2=y;
	ll tmp1=x/b;x1-=tmp1*b;y1+=tmp1*a;
	ll tmp2=y/a;x2+=tmp2*b;y2-=tmp2*a;
	if (abs(x1)+abs(y1)<abs(x)+abs(y)) x=x1,y=y1;
	if (abs(x2)+abs(y2)<abs(x)+abs(y)) x=x2,y=y2;
	if (x1>0) x1-=b,y1+=a;else x1+=b,y1-=a;
	if (y2>0) x2+=b,y2-=a;else x2-=b,y2+=a;
	if (abs(x1)+abs(y1)<abs(x)+abs(y)) x=x1,y=y1;
	if (abs(x2)+abs(y2)<abs(x)+abs(y)) x=x2,y=y2;
}
typedef pair<ll,int> pr;
priority_queue<pr> Q;
void insert(int i){//将对i点的操作方式变换一下的代价为.first 
	Q.push(make_pair(abs(x[i])+abs(y[i])-abs(x[i]-b)-abs(y[i]+a),i));
}
int main()
{
	freopen("seq.in","r",stdin);
	freopen("seq.out","w",stdout);
	scanf("%d%d%d",&n,&a,&b);
	ex_gcd(a,b,tx,ty);
	Gcd=gcd(a,b);a/=Gcd;b/=Gcd;
	for (int i=1;i<=n;i++){
		scanf("%d",&c[i]);
		if (c[i]%Gcd) puts("-1"),exit(0);
		c[i]/=Gcd;
	}
	ll Sx=0,Sy=0;
	n++;
	for (int i=1;i<=n;i++){
		p[i]=c[i]-c[i-1];
		x[i]=-tx*p[i];y[i]=-ty*p[i];
		Min(x[i],y[i]);
		Sx+=x[i];Sy+=y[i];
	}
	if (Sx<0){
		swap(a,b);swap(Sx,Sy);
		for (int i=1;i<=n;i++) swap(x[i],y[i]);
	}
	for (int i=1;i<=n;i++) insert(i);
	//一次区间操作,等价于差分序列上两个单点修改,且和不改变 
	while (Sx){
		int now=Q.top().second;Q.pop();
		Sx-=b;Sy+=a;
		x[now]-=b;y[now]+=a;
		insert(now);
	}
	//一次区间变换等价于在差分序列上两次操作 
	ll ans=0;
	for (int i=1;i<=n;i++) ans+=abs(x[i])+abs(y[i]);
	printf("%lld\n",ans>>1); 
	return 0;
}