zoukankan      html  css  js  c++  java
  • BZOJ4518:[SDOI2016]征途——题解

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

    https://www.luogu.org/problemnew/show/P4072

    Pine开始了从S地到T地的征途。
    从S地到T地的路可以划分成n段,相邻两段路的分界点设有休息站。
    Pine计划用m天到达T地。除第m天外,每一天晚上Pine都必须在休息站过夜。所以,一段路必须在同一天中走完。
    Pine希望每一天走的路长度尽可能相近,所以他希望每一天走的路的长度的方差尽可能小。
    帮助Pine求出最小方差是多少。
    设方差是v,可以证明,v×m^2是一个整数。为了避免精度误差,输出结果时输出v×m^2。

    设第i段划分路的长度为ai,则不难推导出答案为m*sigma(a^2)-(sigma(a))^2。

    维护前缀和s[i],于是设f[i]为前i条路的最少费用,就有f[i]=min(f[i],f[j]+(s[[i]-s[j])^2)。

    愉快的斜率优化维护,大致操作跟BZOJ3675 & 洛谷3648 & UOJ104:[Apio2014]序列分割一样(是的这两道题几乎相同,可能式子不一样……?)复杂度O(nm)。

    ……然而这道题是在去apio之后看的wuvin课件写的,于是……这其实是裸的wqs二分。

    二分划分代价为c,c越大划分次数越少,反之越多(因为c减小时,显然答案在原基础上变得更小,可以选择不继续划分(当然答案还是比原来小),或者可以多花点c来划分序列,于是划分一定变多。)将划分次数逼近为m则此时即为答案。

    复杂度O(nlogV)快到不知道哪里去了,这题n可以为1e5

    #include<queue>
    #include<cmath>
    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    typedef long double dl;
    const int N=50005;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    int n,m,q[N],g[N];
    ll s[N],f[N];
    inline ll sqr(ll x){return x*x;}
    inline dl suan(int k,int j){
        if(s[k]==s[j])return -1e18;
        return (dl)(f[k]-f[j]+sqr(s[k])-sqr(s[j]))/(s[k]-s[j]);
    }
    bool pan(ll c){
        int l=0,r=0;
        for(int i=1;i<=n;i++){
            while(l<r&&suan(q[l],q[l+1])<(dl)2*s[i])l++;
            f[i]=f[q[l]]+sqr(s[i]-s[q[l]])+c;
            g[i]=g[q[l]]+1;
            while(l<r&&suan(q[r-1],q[r])>suan(q[r],i))r--;
            q[++r]=i;
        }
        return g[n]<=m;
    }
    ll solve(ll l,ll r){
        ll ans;
        while(l<r){
            ll mid=(l+r)>>1;
            if(!pan(mid))l=mid+1;
            else{
                ans=m*(f[n]-mid*m)-sqr(s[n]);r=mid;//这里括号里面的m改为g[n]就会wa不知道为什么有谁能解答一下吗
    //主要是感觉最后反正g[n]也会变成m就乘了g[n]结果就90分了…… } }
    return ans; } int main(){ n=read(),m=read(); for(int i=1;i<=n;i++)s[i]=s[i-1]+read(); printf("%lld ",solve(0,sqr(s[n]))); return 0; }

    +++++++++++++++++++++++++++++++++++++++++++

    +本文作者:luyouqi233。               +

    +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/ +

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    deepin 安装版本管理工具
    deepin 安装maven
    deepin 安装 idea
    启动VMware环境下的Linux操作系统,添加新分区
    Centos6.*安装vsftpd
    easyui-datebox 年月视图显示
    oracle-数据库泵EXPDP导出用户下所有
    Oracle虚拟机配置
    JSON理解
    Python语法基础_04.元组、函数-上
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/9030055.html
Copyright © 2011-2022 走看看