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;
}