zoukankan      html  css  js  c++  java
  • P1714切蛋糕(不定区间最值)

    题面

    今天是小Z的生日,同学们为他带来了一块蛋糕。这块蛋糕是一个长方体,被用不同色彩分成了N个相同的小块,每小块都有对应的幸运值。

    小Z作为寿星,自然希望吃到的第一块蛋糕的幸运值总和最大,但小Z最多又只能吃M小块(M≤N)的蛋糕。

    吃东西自然就不想思考了,于是小Z把这个任务扔给了学OI的你,请你帮他从这N小块中找出连续的k块蛋糕(k≤M),使得其上的幸运值最大。


    不定区间长度还是第一次遇到

    分析 考虑朴素写法,非常直观。

    对于以第i个元素结尾的子段,最大的子段和P(i)可以表示为

    P [ i ] = max { sum [ i ] - sum [ j ] , j 属于 [ i-M, i-1 ]

    于是有ans = max [ P [ i ] ]

    算法的复杂度是O ( N M )

    在题目的范围下TLE是必然的

    将上面P[i]的计算式改写为

    P [ i ] = sum [ i ] - min { sum [ j ] },j属于 [ i-M , i-1 ]

    显然,在每次获取 P [ i ] 的时候,Sum [ i ] 是定值,所以 P [ i ] 由 Sum [ j ] 的最小值确定。

    于是我们就要想方设法在优于O(M)的时间内实现获取最小的 Sum [ j ] 。

    最优时,Sum [ j ] 的性质:

    (1)Sum [ j ] ≤ Sum [ x ]  x∈ [ i-M , i-1 ]且x≠j

    (2)j∈[ i-M , i-1 ]

    枚举加优化

    考虑设计这样一个数据结构,在更低的时间复杂度内获取最优Sum [ j ] 。

    ①单调队列

    #include <iostream>
    using namespace std;
    #define max(a,b) (a>b?a:b)
    const int maxn=500009;
    int a[maxn],zhui[maxn];
    int q[maxn],p[maxn],ans=-9999999,spfa[maxn];
    int main()
    {
        int n,m,tail=0,head=1;
        cin>>n>>m;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            zhui[i]=zhui[i-1]+a[i];
        }
        for(int i=1;i<=n;i++)
        {
            while(tail>=head&&q[tail]>=zhui[i])    tail--;
            q[++tail]=zhui[i];p[tail]=i;
            while(p[head]+m<=i)    head++;
            spfa[i]=q[head];
        }
        for(int i=1;i<=n;i++)
            ans=max(ans,zhui[i]-spfa[i-1]);
        cout<<ans;
    }
    View Code

    ②ST稀疏表

    #include <bits/stdc++.h> 
    using namespace std;
    const int maxn=500009;
    int a[maxn],zhui[maxn];
    int ans=-9999999,dis[maxn][22];
    int query(int l,int r){
        int k=log2(r-l+1);
        return min(dis[l][k],dis[r+1-(1<<k)][k]);
    }
    int main()
    {
        int n,m;
        cin>>n>>m;
        for(int i=1;i<=n;i++)
        {
            int t;
            cin>>t;
            zhui[i]=zhui[i-1]+t;
            dis[i][0]=zhui[i];
        }
        for(int j=1;j<=log2(n);j++)
        {
            for(int i=1;i+(1<<j)-1<=n;i++)
                dis[i][j]=min(dis[i][j-1],dis[i+(1<<(j-1))][j-1]);
        }
        for(int i=1;i<=n;i++)
        {
            int l=i-m;//等于是求i-m+1到第i项 
            if(l<0)        l=0;
            ans=max(ans,zhui[i]-query(l,i));
        }
        cout<<ans;
    }
    View Code
  • 相关阅读:
    素数筛法
    UVA, 967 Circular
    软件开发一些常用工具
    iOS 一些常用方法笔记
    iOS 项目调试
    UINavigation的基本使用
    Tomcat多实例部署
    五联疫苗介绍
    互联网公司架构
    分布式事务
  • 原文地址:https://www.cnblogs.com/iss-ue/p/12490538.html
Copyright © 2011-2022 走看看