ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

220722 T2 序列(ST表+分治)

2022-07-23 15:31:40  阅读:158  来源: 互联网

标签:ch 220722 int ll T2 ST 代价 id op


题目描述 小 B 喜欢玩游戏。 有一天,小 B 在玩一个序列上的游戏,他得到了正整数序列{ai}以及一个常数c 。 游戏规则是,玩家可以对于每一个ai 分别加上一个非负整数x ,代价为 x2,完成所有操作之后,需要额外花费的代价就是所有相邻位置上数之差的绝对值总和再乘上c 。 小 B 觉得这个游戏很简单,想以最小的代价通过关卡,请你来帮助他求出总代价的最小值。 输入格式 第一行两个整数n,c 第二行 n个整数表示{ai} 输出格式 一行一个整数表示最小代价。    

花了我一天多的时间......

先放代码:(注释应该比较详细了)

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10,T=18;
int n,c,a[N],lg[N],ans;
#define fi first 
#define se second 
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;
}
pair<int,int> st[N][T];
pair<int,int> get(int l,int r){
    int p=lg[r-l+1];
    return max(st[l][p],st[r-(1<<p)+1][p]);
}
struct node{
    int x,h;//x是往上抬的步数总和、h是抬高到的高度 
};

void ST(){//ST表求区间max 
    lg[1]=0;
    for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
    for(int j=1;j<=T-1;j++)
        for(int i=1;i+(1<<j-1)<=n;i++)
            st[i][j]=max(st[i][j-1],st[i+(1<<j-1)][j-1]);
}

node solve(int l,int r,int k){
    if(l>r) return (node){0,-1};
    int id=get(l,r).se;
    node L=solve(l,id-1,a[id]),R=solve(id+1,r,a[id]);
    if(L.h!=-1&&L.h!=a[id]||R.h!=-1&&R.h!=a[id]) return (node){0,0};
    //一边没有提上来,之后不需要提了(大佬:直接溜了) 
    int len=r-l+1,x=L.x+R.x,op=0,ll=0,rr=1e7;
    if(l==1||r==n) op=1;//边界
    else op=2;
    while(ll<=rr){
        int mid=(ll+rr)>>1;
        if(2*x+len+2*len*mid>op*c) rr=mid-1;
        else ll=mid+1;
    }//二分寻找应该向上抬多少层
    if(ll<1) return (node){x,a[id]};//抬不了
    ll=min(ll,k-a[id]);//抬的高度不能超过k
    ans+=(2*x+len+2*(x+(ll-1)*len)+len)*ll/2-op*c*ll;//等差数列求和
    return (node){x+ll*len,a[id]+ll}; 
}

signed main(){
    n=read();c=read();
    for(int i=1;i<=n;i++){
        a[i]=read();
        st[i][0]=make_pair(a[i],i);
        ans+=c*(i!=1)*abs(a[i]-a[i-1]);//初始代价 
    }
    ST();int k=get(1,n).fi;
    solve(1,n,k);
    cout<<ans<<endl;
    return 0;
}
/*
4 3
2 1 2 3
*/

原数列将数值看做高度,相当于是一个连绵起伏,蜿蜒曲折的山脉(文笔真好),我们要找到波谷,对其尝试往上抬,抬的具体数值用二分来寻找。

大佬的草稿,用于解释solve()的步骤:(仰望大佬)

 

标签:ch,220722,int,ll,T2,ST,代价,id,op
来源: https://www.cnblogs.com/yhxnoerror/p/16512119.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有