校内试题 6月25日

这个难度有点迷,..我就捋一下顺序然后说吧,这个题目难度不是按照T题的日常难度来排的,我就顺便排一下..
暴0不开心 什么时候我能够AK一次呢 qwqq

CCL 的消遣(CCL)
[题目描述]
AS we know,CCL 是一个很无聊很无聊很无聊的人.有一天,CCL 注意到地面上有很多棍子,
于是,CCL 决定用这些棍子来消磨时间(这是要有多无聊啊).
CCL先将这些棍子排成一排.每根棍子有一个长度.CCL一次可以将2个相邻的棍子合并成
一根更长的棍子,合并出的棍子的长度为原来 2 根棍子的长度之和(具体的过程请参考样
例).CCL 想用最少的合并次数来将这些棍子变成一个长度不降的序列.
[输入格式]
输入文件的第一行有一个正整数 n,表示棍子的数目.
接下来一行 n 个正整数,依次表示每根木棍的长度.
[输出格式]
输出文件一行仅一个数,表示最少的合并次数.
[样例输入]
5
8 2 7 3 1
[样例输出]
3
[样例解释]
最优方案是将后 4 根木棍合并,形成一个长度为 13 的棍子,共需要 3 次合并操作.
合并后的序列为:8,13.
[数据范围]
10%的数据,N<=1500
20%的数据,N<=5000
50%的数据,N<=200000
100%的数据,N<=1000000,每根棍子的长度<=maxlongint

暴力过10分.. 那就写正解好了

#define fre yes

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int maxn = 1000005;
long long arr[maxn];
long long w[maxn],f[maxn],c[maxn];

long long n,k,ans;

template<typename T>inline void read(T&x)
{
    x = 0;char c;int lenp = 1;
    do { c = getchar();if(c == '-') lenp = -1; } while(!isdigit(c));
    do { x = x * 10 + c - '0';c = getchar(); } while(isdigit(c));
     x *= lenp;
}

int main()
{
#ifdef fre
    freopen("CCL.in","r",stdin);
    freopen("CCL.out","w",stdout);
#endif
    memset(f,0x3f3f3f3f,sizeof(f));

    read(n);
    for (int i=1;i<=n;i++)
    {
        int x;
        read(x);
        arr[i] = x;
        arr[i] = arr[i-1] + arr[i];
    }
    
    long long l = 1,r = 1; f[0] = 0; w[0] = 0;
    for (int i=1;i<=n;i++)
    {
        while(l < r && arr[i] >= f[w[l+1]]) l++;
        f[i] = arr[i] - arr[w[l]] + arr[i];
        c[i] = c[w[l]] + i - w[l] - 1;
        while(r > l && f[i] <= f[w[r]]) r--;
        w[++r] = i;
    } printf("%lld\n",c[n]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Steinway/p/9226374.html