「杂题乱刷2」CF601B

怎么没人写好写的 ST 表呢。

题目链接

CF601B Lipshitz Sequence (luogu)

CF601B Lipshitz Sequence (codeforces)

解题思路

其实一眼可以发现选相邻的是最优的。

证明:

若这个区间中的数字为 [a,b,c],此时若选择 a,c 这两个数字,则必有 |ac|2|ab||ac|2|bc|,两式相加得 |ac||ab|+|bc|,此时分讨三个数的大小关系:

  • abc,此时式子为 caba+cb,化简得 00,说明此时选相邻两个数与选 a,c 两个数相比不劣。

  • acb,此时式子为 caba+bc,化简得 2c2b,由于 cb,因此 2cb,不符合原命题,说明此时选相邻两个数与选 a,c 两个数相比不劣。

  • bac,此时式子为 caab+cb,化简得 2b2a,由于 ba,因此 2b2a,不符合原命题,说明此时选相邻两个数与选 a,c 两个数相比不劣。

  • bca,此时式子为 acab+cb,化简得 2b2c,由于 bc,因此 2b2c,不符合原命题,说明此时选相邻两个数与选 a,c 两个数相比不劣。

  • cab,此时式子为 acba+bc,化简得 2a2b,由于 ab,因此 2a2b,不符合原命题,说明此时选相邻两个数与选 a,c 两个数相比不劣。

  • cba,此时式子为 acab+bc,化简得 00,说明此时选相邻两个数与选 a,c 两个数相比不劣。

因此选相邻两个数字一定不劣,此时设 i[1,n1]bi=|aiai+1|,则答案为 i=lr1j=ir1maxk=ijbk

这是一个经典的问题,直接 ST 表加二分即可,注意此时需要预处理每个 L,R 的节点,这样复杂度是 O(nlogn+nq) 的,不会 TLE,否则直接做是 O(qnlogn) 的,会 TLE。

直接单调栈也能做,我写的是 ST 表。

参考代码

#include<bits/stdc++.h>
using namespace std;
#define re register
#define ll int
#define forl(i,a,b) for(re ll (i)=(a);i<=(b);(i)++)
#define forr(i,a,b) for(re ll (i)=(a);i>=(b);(i)--)
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define QwQ return 0;
ll pw(ll x){return 1ll<<x;}
ll _t_;
ll lg[1000110];
void Init(){
    forl(i,2,1e6+5)
        lg[i]=lg[i>>1]+1;
}
ll n,q;
ll a[100010];
ll b[100010];
ll l,r;
ll maxn[100010][20];
ll nL[100010],nR[100010];
ll query(ll l,ll r)
{
    if(l>r)
        return (ll)2e9;
    ll LG=lg[r-l+1];
    return max(maxn[l][LG],maxn[r-pw(LG)+1][LG]);
}
long long ans;
void _clear(){}
void solve()
{
    _clear();
    cin>>n>>q;
    forl(i,1,n)
        cin>>a[i];
    forl(i,1,n-1)
        b[i]=abs(a[i+1]-a[i]),
        maxn[i][0]=b[i];
    n--;
    forl(j,1,19)
        forl(i,1,n-pw(j)+1)
            maxn[i][j]=max(maxn[i][j-1],maxn[i+pw(j-1)][j-1]);
    l=1,r=n;
    ans=0;
    forl(i,l,r)
    {
        ll L=l,R=i;
        while(L<R)
        {
            ll Mid=(L+R)/2;
            if(query(Mid,i-1)<b[i])
                R=Mid;
            else
                L=Mid+1;
        }
        ll nl=L;
        L=i,R=r;
        while(L<R)
        {
            ll Mid=(L+R+1)/2;
            if(query(i+1,Mid)<=b[i])
                L=Mid;
            else
                R=Mid-1;
        }
        ll nr=L;
        if(query(nl,i)==b[i] && query(i,nr)==b[i])
            nL[i]=nl,
            nR[i]=nr;
        else
            nL[i]=nR[i]=i;
    }
    while(q--)
    {
        cin>>l>>r;
        r--;
        forl(i,l,r)
        {
            ll nl=max(nL[i],l),nr=min(nR[i],r);
            ans+=1ll*b[i]*(i-nl+1)*(nr-i+1);
        }
        cout<<ans<<endl;
        ans=0;
    }
}
int main()
{
	Init();
    IOS;
    _t_=1;
    while(_t_--)
        solve();
    QwQ;
}
posted @   wangmarui  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
历史上的今天:
2024-01-28 「比赛总结」CF Round 921 Div.2 比赛总结
点击右上角即可分享
微信分享提示