码迷,mamicode.com
首页 > 其他好文 > 详细

[斜率优化DP] codeforces 673E. Levels and Regions

时间:2016-05-13 00:27:50      阅读:291      评论:0      收藏:0      [点我收藏+]

标签:

题意:
要把1n分成k组,每组内的数必须连续,组与组不相交且每个数必须属于一个组,并且任意i有一个参数ti
如果[l,r]为一组,那么从l走到l+1的概率是tltl,从l+1走到l+2的概率是tltl+1tl+1tl+1,依次类推,从l要么走到l+1,要么原地不动,那么组[l,r]的费用就是从l走到r的期望次数。现在要分成k组,让总费用最小,每个数仅能属于一个组。
题解:
先推期望公式。
sum[i]=ij=1tirev[i]=ij=11ti,那么从1走到i的期望exc[i]=exc[i?1]+sum[i]ti
然后观察得到从l走到r的期望公式exc[l][r]exc[r]?exc[l?1]?sum[l?1]?(rev[r]?rev[l?1])
然后设dp[i][j]表示以前i个数成j段的最小费用。
转移:dp[i][j]=min(dp[l][j?1]+exc[l+1][i])
发现这是个O(n2?k)的转移。
当我们的i固定的时候,就是要在[1,i?1]找一个最优解l,观察形式得出可以斜率优化,O(n?k)的复杂度就可以过了。
斜率优化可以看这里
推出斜率公式为

gp(j,k)=y(j,p)?y(k,p)sum[j]?sum[k]

其中y(x,p)=dp[x][p]?exc[x?1]+sum[x?1]?rev[x?1]
并且推出结论k<j<ig(j,k)<rev[i],那么对于i来说,j要优于k
由于rev[i]i递增而递增,当求解l的时候,无需二分,只需要维护单调队列的top最优就可以了。
代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
double exc[N] = {0}, sum[N] = {0}, rev[N] = {0};
double t[N];
double dp[N][55];
inline double y(int x, int p){
    return dp[x][p] - exc[x] + sum[x]*rev[x];
}
inline double g(int j, int k, int p){
    return (y(j, p)-y(k, p))/(sum[j]-sum[k]);
}
inline double cal(int l, int i){
    return exc[i]-exc[l]-(rev[i]-rev[l])*sum[l];
}
int q[N], top, tail;
inline void add(int i, int k){
    while(top < tail-1 && g(i, q[tail-1], k) < g(q[tail-1], q[tail-2], k)) tail--;
    q[tail++] = i;
}
inline int getmax(int i, int k){
    while(top < tail-1 && g(q[top+1], q[top], k) < rev[i]) top++;
    return q[top];
}
int main(){
    int n, K;
    scanf("%d%d", &n, &K);
    for(int i = 1; i <= n; ++i) scanf("%lf", t+i);
    for(int i = 1; i <= n; ++i){
        sum[i] = sum[i-1] + t[i];
        rev[i] = rev[i-1] + 1.0/t[i];
        exc[i] = exc[i-1] + sum[i]/t[i];
    }
    for(int i = 1; i <= n; ++i) dp[i][1] = exc[i];
    for(int k = 2; k <= K; ++k){
        top = tail = 0;
        q[tail++] = 0;
        for(int i = 1; i <= n; ++i) add(i, k-1);
        for(int i = 1; i <= n; ++i){
            if(i >= k){
                int l = getmax(i, k-1);
                dp[i][k] = dp[l][k-1] + cal(l, i);
            }
            else dp[i][k] = 1e50; //不可能状态
        }
    }
    printf("%.10f\n", dp[n][K]);
}

[斜率优化DP] codeforces 673E. Levels and Regions

标签:

原文地址:http://blog.csdn.net/kg20006/article/details/51346853

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!