CF1582 E. Pchelyonok and Segments(dp+贪心)

目录

Description

\(n\) 个数中选择 \(k\) 个子段,要求 \(sum(l_1 \ldots r_1) < sum(l_2 \ldots r_2) < \ldots < sum(l_k \ldots r_k)\)

而且区间 \([l_1,r_1]\) 长度为 \(k\),以此类推,\([l_k,r_k]\) 区间长度为 \(1\)

并且各个区间 \(r_i<l_{i+1}\)

State

\(1 \le n \le 10^5\)

\(a_1, a_2, \ldots, a_n(1 \le a_i \le 10^9)\)

Input

5
1
1
3
1 2 3
5
1 1 2 2 3
7
1 2 1 1 3 2 6
5
9 6 7 9 7

Output

1
1
2
3
1

Solution

很容易发现 \(k\) 不会超过 \(\sqrt{n}\) ,这样的复杂度引领着向 \(dp\) 上靠拢

为方便起见,将整个数组翻转过来,也就是说第一个区间长度为 \(1\),且权值最大

容易定义 \(dp_{ki}\)\(k\) 段从 \(i\) 开始的区间权值为 \(dp_{ki}\)

而根据贪心,当前区间的权值越大,那么可以保证 \(k\) 越大

根据 \(dp_{ki}\) 可以推得 \(max(dp_{(k+1)(i+k)})\)

最后需要注意的是,如果 \(dp_{ki}<dp_{k(i-1)}\),那么 \(dp_{ki}=dp_{k(i-1)}\),这样可以保证下一步是最优的


Code

const int N = 1e5 + 5;
 
    int n, m, k, _;
    int a[N];
    ll dp[500 + 5][N];
    ll sum[N];

signed main()
{
    // IOS;
    rush(){
        sd(n);
        for(int k = 1; k <= 500; k ++){
            for(int i = n; i; i --){
                dp[k][i] = 0;
            }
        }
        per(i, 1, n) sd(a[i]);
        for(int i = 1; i <= n; i ++){
            sum[i] = sum[i - 1] + a[i];
        }
        for(int i = 1; i <= n; i ++) dp[1][i] = a[i];
        int ans = 1;
        for(int k = 1; k <= 500; k ++){
            for(int i = 1; i <= n; i ++){
                dp[k][i] = max(dp[k][i], dp[k][i - 1]);
                // dp[k + 1][i + k] = dp[k + 1][i + k - 1];
                if(sum[i + 2 * k] - sum[i + k - 1] < dp[k][i] && i + 2 * k <= n){
                    dp[k + 1][i + k] = max(dp[k + 1][i + k], sum[i + 2 * k] - sum[i + k - 1]);
                    ans = k + 1;
                }
            }
        }
        pd(ans);
    }
    // PAUSE;
    return 0;
}

posted @ 2021-11-01 11:40  Bcoi  阅读(74)  评论(0)    收藏  举报