首页 > 代码库 > bzoj4518

bzoj4518

http://www.lydsy.com/JudgeOnline/problem.php?id=4518

水了一发斜率优化 好久没写了 调了一个晚上

dp[i][j]:第i天走到了第j个休息站 

dp[i][j] = min(dp[i-1][x] + (s[i]-s[x]-v)^2)v是平均数=s[n]/m

然后我们化简一下得到了一个式子 (h[j]-h[k])/(s[j]-s[k])/2<=s[i]是不优的(这里我好像把小于等于号推反了,这里是对的)那么我们就可以斜率优化了

然后写了很长时间

注意:1.队列是l<r 2.要赋初值

技术分享
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3010;
int n, m;
ll v;
ll s[N], h[N], dp[N][N];
int q[N];
double slope(int j, int k) 
{
    return ((double)h[j] - (double)h[k]) / ((double)s[j] - (double)s[k]) / 2.0;
}
void solve()
{
    for(int i = 0; i <= n; ++i) dp[1][i] = (s[i] - v) * (s[i] - v);
    for(int i = 2; i <= m; ++i)
    {
        int l = 1, r = 0;  q[++r] = 0;
        dp[i][0] = v * v + dp[i - 1][0];
        for(int j = 0; j <= n; ++j) h[j] = dp[i - 1][j] + s[j] * s[j] + 2 * v * s[j];
        for(int j = 1; j <= n; ++j) 
        {
            while(l < r && slope(q[l], q[l + 1]) <= s[j]) ++l;
            dp[i][j] = min(dp[i - 1][q[l]] + (s[j] - s[q[l]] - v) * (s[j] - s[q[l]] - v), dp[i - 1][j] + v * v);
            while(l < r && slope(j, q[r]) <= slope(q[r - 1], q[r])) --r;
            q[++r] = j;
        }
    }
    printf("%lld\n", dp[m][n] / m);
}
int main()
{
    freopen("menci_journey.in", "r", stdin);
    freopen("menci_journey.out", "w", stdout);
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i)
    {
        ll x; scanf("%lld", &x);
        s[i] = s[i - 1] + x * (ll)m; 
    }
    v = s[n] / (ll)m;
    solve();
    fclose(stdin); fclose(stdout);
    return 0;
}
View Code

 

bzoj4518