zoukankan      html  css  js  c++  java
  • BZOJ2800 [Poi2012]Leveling Ground 【扩展欧几里得 + 三分 + 堆】

    题目链接

    BZOJ2800

    题解

    区间加极难操作,差分之后可转化为两点一加一减
    那么现在问题就将每个点暂时独立开来

    先判定每个点是否被((A,B))整除,否则无解
    之后我们先将(A,B)化为互质,所有数除一个((A,B))
    求得

    [Ax + By = 1 ]

    那么对于点(d[i]),满足

    [d[i] = A(xd[i] + kB) + B(yd[i] - kA) ]

    其中(k)可以取任意值
    我们对于单点的目标,是最小化

    [|xd[i] + kB|+|yd[i] - kA| ]

    两个绝对值相加是一个单峰函数,利用三分法即可得出(k)
    从而得到每个点目前最优解(X[i] = xd[i] + kB,Y[i] = yd[i] - kA)

    但是我们做到了单个点最优,但整体不一定合法,我们必须满足正负操作次数相同

    [Asumlimits_{i = 1}^{n}X[i] + Bsumlimits_{i = 1}^{n}Y[i] = 0 ]

    而由于(sum d[i] = 0)
    故我们只需保证(T = sum X[i] = 0)
    显然我们只需改变(frac{T}{B})
    对于每个(X[i])我们计算出它改变一次的代价,用一个堆维护即可

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<queue>
    #include<cmath>
    #include<map>
    #define REP(i,n) for (register int i = 1; i <= (n); i++)
    #define cls(s) memset(s,0,sizeof(s))
    #define LL long long int
    using namespace std;
    const int maxn = 100005,maxm = 100005,INF = 1000000000;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    struct pr{LL v,i;};
    inline bool operator <(const pr& a,const pr& b){
    	return a.v > b.v;
    }
    priority_queue<pr> q;
    LL n,A,B,X,Y,d[maxn],h[maxn],xx[maxn],yy[maxn],dd;
    void exgcd(LL a,LL b,LL& d,LL& x,LL& y){
    	if (!b){d = a; x = 1; y = 0;}
    	else exgcd(b,a % b,d,y,x),y -= (a / b) * x;
    }
    inline LL cost(int i,LL k){
    	return abs(X * d[i] + k * B) + abs(Y * d[i] - k * A);
    }
    void workmin(){
    	REP(i,n){
    		LL l = -INF,r = INF,lmid,rmid,L,R,K;
    		while (r - l >= 3){
    			lmid = (l + l + r) / 3;
    			rmid = (r + l + r) / 3;
    			L = cost(i,lmid);
    			R = cost(i,rmid);
    			if (L == R){
    				if (cost(i,lmid - 1) < L) r = rmid;
    				else l = lmid;
    			}
    			else if (L > R) l = lmid;
    			else r = rmid;
    		}
    		K = l;
    		for (int j = l + 1; j <= r; j++)
    			if (cost(i,j) < cost(i,K)) K = j;
    		xx[i] = X * d[i] + K * B;
    		yy[i] = Y * d[i] - K * A;
    	}
    }
    inline LL price(int i){
    	return abs(yy[i] - dd * A) + abs(xx[i] + dd * B) - abs(xx[i]) - abs(yy[i]);
    }
    void print(){
    	//REP(i,n) printf("(%lld,%lld)
    ",xx[i],yy[i]); puts("");
    	LL ans = 0;
    	REP(i,n) ans += abs(xx[i]) + abs(yy[i]);
    	printf("%lld
    ",ans >> 1);
    }
    void workok(){
    	LL sum = 0;
    	REP(i,n) sum += xx[i];
    	sum /= B;
    	dd = sum > 0 ? -1 : 1; sum = abs(sum);
    	REP(i,n) q.push((pr){price(i),i});
    	pr u;
    	while (sum--){
    		u = q.top(); q.pop();
    		xx[u.i] += dd * B;
    		yy[u.i] -= dd * A;
    		q.push((pr){price(u.i),u.i});
    	}
    }
    int main(){
    	n = read(); A = read(); B = read(); LL D;
    	exgcd(A,B,D,X,Y); A /= D; B /= D;
    	REP(i,n){
    		h[i] = read(); 
    		if (h[i] % D){puts("-1"); return 0;}
    		h[i] /= D; d[i] = h[i] - h[i - 1];
    	}
    	n++;
    	d[n] = -h[n - 1];
    	workmin();
    	workok();
    	print();
    	return 0;
    }
    
    
  • 相关阅读:
    get the default proxy by Powershell
    import-module in $profile
    Basic Queries (LINQ to XML)
    xpath中双斜杠的作用// double slash
    Powershell 常见问题
    touch all contents in a folder recursively
    What's the difference between HEAD, working tree and index, in Git?
    beyond compare 比较文本 standard alignment VS unaligned
    bat文件中调用传参的问题
    bacth参数说明 cmd parameter
  • 原文地址:https://www.cnblogs.com/Mychael/p/9241631.html
Copyright © 2011-2022 走看看