Description
农夫约翰正在建造一个美丽的花园,在这个过程中需要移动大量的泥土。花园由N个花圃(1≤N≤100,000)组成,
第i个花圃最开始有Ai个泥土。 农夫约翰想要重新整理花园,使每个花圃最后有Bi个泥土。Ai和Bi都是0...10范围
内的整数。为了整理花园,Farmer John有几个选择:他可以购买一个单位的泥土,并将它放在他选择的花圃中,
用X单位的钱。 他可以从他选择的花圃上清除一块泥土,并用Y单位的钱运出去。他还可以用Z*|i-j|的花费将一单
位的泥土从花圃i运输到花圃j。请计算农民约翰完成他的绿化项目的最低总成本。
Input
第一行输入包含N,X,Y和Z(0≤X,Y≤10^8; 0≤Z≤1000)。
行i + 1包含整数Ai和Bi。
Output
请输出FJ需要花在园林绿化上的最低总成本。
Sample Input
4 100 200 1
1 4
2 3
3 2
4 0
1 4
2 3
3 2
4 0
Sample Output
210
HINT
Source
DP
首先一个naive的dp是用min edit distance,这个是O((10n)^2)的
还是考虑DP
首先我们把序列写成若干个±1的形式
然后就可以理解为有一堆±1配对或移除,问最小代价
有3个性质:
第一:匹配的±1一定不会相交
显然,把它们改成包含一定更优
第二:可以分层DP
把每一层都写成±1交替的形式
这个的证明,如果有一段和>0,那么我们一定要移除其中的一个1,那么我们平移某个端点,使得被移除的1在端点处不会更劣,<0同理
第三:对于每一层的匹配,两个位置i,j配对的花费是min(x + y, z * dis)我们把x + y更小的(i,j)定义为长区间,那么存在包含关系的一定是长区间包含若干个短区间
这个证明很容易,分类讨论,容易发现如果长包含长或者短包含短可以通过调整变得更优
然后就可以DP了
#include <bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define fill( x, y ) memset( x, y, sizeof x )
#define copy( x, y ) memcpy( x, y, sizeof x )
using namespace std;
typedef long long LL;
typedef pair < int, int > pa;
const int MAXN = 100010;
const LL INF = 1e16;
int n, x, y, z, cnt, type[MAXN];
LL f[MAXN], g[MAXN], ans;
map < int, int > m;
vector < int > v[MAXN];
inline void dp(vector < int > &v, LL *f)
{
LL sum1 = 0, sum2 = 0, mn = INF;
int n = v.size();
for( int i = 1, j = 0 ; i < n ; i += 2 )
{
if( i > 1 ) sum1 += 1LL * z * abs( v[ i - 1 ] - v[ i - 2 ] ), mn += 1LL * z * abs( v[ i - 1 ] - v [ i - 2 ] );
while( j < i && x + y < 1LL * z * abs( v[ i ] - v[ j ] ) )
{
if( j ) sum2 += 1LL * z * abs( v[ j ] - v[ j - 1 ] );
mn = min( mn, sum1 - sum2 + x + y + ( j ? f[ j - 1 ] : 0 ) );
j += 2;
}
f[ i ] = min( mn, 1LL * z * abs( v[ i ] - v[ i - 1 ] ) + f[ i - 2 ] );
}
}
inline LL solve(vector < int > &v, int c)
{
int n = v.size(); LL ret = 0;
if( n == 1 ) return c;
dp( v, f );
if( !( n & 1 ) ) return f[ n - 1 ];
reverse( v.begin(), v.end() );
dp( v, g );
reverse( g, g + n );
ret = c + min( f[ n - 2 ], g[ 1 ] );
for( int i = 1 ; i < n - 2 ; i += 2 ) ret = min( ret, f[ i ] + g[ i + 2 ] + c );
return ret;
}
int main()
{
#ifdef wxh010910
freopen( "data.in", "r", stdin );
#endif
scanf( "%d%d%d%d", &n, &x, &y, &z );
for( int i = 1, sum = 0, last = 0 ; i <= n ; i++ )
{
int a, b, d, len;
scanf( "%d%d", &a, &b );
if( a == b ) continue;
d = ( a - b > 0 ) ? 1 : -1;
len = max( a - b, b - a );
while( len-- )
{
if( d == last ) sum += d;
if( m.find( sum ) == m.end() ) type[ m[ sum ] = ++cnt ] = d;
v[ m[ sum ] ].pb( i );
last = d;
}
}
for( int i = 1 ; i <= cnt ; i++ ) ans += solve( v[ i ], type[ i ] > 0 ? y : x );
cout << ans << endl;
}