#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i,s,t) for(ll i = s;i <= t;++i) // 定义正向循环宏
#define per(i,t,s) for(ll i = t;i >= s;--i) // 定义逆向循环宏
const ll N = 5e3 + 5; // 定义最大砖块数
ll n; // 砖块总数
ll a[N] = {}; // 存储每块砖的宽度
ll sum[N] = {}; // 前缀和数组,sum[i]表示前i块砖的总宽度
ll dp[N][N] = {}; // dp[l][r]表示从第l到第r块砖的最大美观度
ll pre[N][N] = {}; // pre[l][r]表示从第1到第l行,第1到第r列的最大美观度
// 快速读取函数
inline ll read() {
ll x = 0;
ll y = 1;
char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') y = -y;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = (x << 3) + (x << 1) + (c ^ '0');
c = getchar();
}
return x * y;
}
// 快速写入函数
inline void write(ll x) {
if(x < 0) {
putchar('-');
write(-x);
return;
}
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
int main() {
freopen("C.in","r",stdin);
freopen("C.out","w",stdout);
n = read(); // 读取砖块数量
rep(i,1,n) {
a[i] = read(); // 读取每块砖宽度
sum[i] = sum[i - 1] + a[i]; // 计算前缀和
}
// 动态规划求解
rep(l,2,n) { // 枚举起始砖块l
dp[l][l] = pre[l - 1][l - 1]; // 初始化dp值
pre[l][l] = max(dp[l][l], pre[l - 1][l]); // 更新pre值
ll cnt = 0; // 计数器
ll pos = l; // 位置指针
rep(r,l+1,n) { // 枚举结束砖块r
dp[l][r] = dp[l][r - 1]; // 初始化为不包含r的情况
// 寻找满足条件的pos
while(pos >= 3 && sum[r-1]-sum[l-1] > sum[l-1]-sum[pos-1])
pos--;
// 如果找到满足条件的位置
if(sum[r-1]-sum[l-1] == sum[l-1]-sum[pos-1]) {
cnt++;
dp[l][r] = max(dp[l][r], pre[pos-1][l-1] + cnt);
}
pre[l][r] = max(pre[l-1][r], dp[l][r]); // 更新pre值
}
}
write(pre[n][n]); // 输出结果
fclose(stdin);
fclose(stdout);
return 0;
}小丁砌墙
题目描述
小丁是一名优秀的工人,现在他拥有
n
n 块砖块,第
i
i 块砖块的高度为
1
1,宽度为
a
i
a
i
,他要用这
n
n 块砖块砌一堵最美观的墙。
小丁很在乎砖块的顺序,所以他在砌墙过程中始终按照从
1
1 到
n
n 的顺序使用砖块。
小丁将在第一行从左到右将若干砖块排列在一起,而在第二行中他会从右到左依次排列砖块,并且保证第一行的右边缘和第二行的右边缘对齐;在第三行中,他会从左到右依次排列砖块,保证第三行的左边缘和第二行的左边缘对齐;以此类推,直到所有砖块用完。小丁可以使用任意的行数建造这堵墙(仅有一或两行也可以)。
小丁的砌墙技术十分高超,所以一块砖块的下方不需要有另一块砖块直接支撑,例如当砖块的宽度为
1
1
2
1 1 2 时,第一行为第一块砖块,第二行为第
2
,
3
2,3 块砖块也是一种合法的砌墙方式。
小丁将一种砌墙方式的的美观度定义为与恰好四个砖块接触的位置的总数,例如当砖块的宽度为
1
1
1
1
2
2
1 1 1 1 2 2,第一行从左到右排列第
1
,
2
,
3
,
4
1,2,3,4 块砖块,第二行从右到左排列第
5
,
6
5,6 块砖块时,第
2
,
3
,
5
,
6
2,3,5,6 块砖块接触了同一个位置(即组成的
2
×
4
2×4 的墙的中心位置),因此这种砌墙方式的美观度为
1
1。
小丁想知道,对于给定的这
n
n 块砖块,在所有砌墙方式中最大的美观度是多少?
输入格式
第一行一个正整数
n
n,表示砖块总数。
第二行
n
n 个正整数
a
1
,
a
2
,
⋯
,
a
n
a
1
,a
2
,⋯,a
n
,表示砖块的宽度。
输出格式
一行一个整数,表示最大的美观度。
样例 1 输入
6
2 1 1 1 1 2
样例 1 输出
2
样例 1 解释
一种美观度是
2
2 的方案是,第一行从左到右排列第
1
,
2
,
3
1,2,3 块砖块,第二行从右到左排列第
4
,
5
,
6
4,5,6 块砖块,此时第
1
,
2
,
5
,
6
1,2,5,6 块砖块接触了同一个位置,第
2
,
3
,
4
,
5
2,3,4,5 块砖块接触了同一个位置,因此美观度为
2
2。
其余样例见下发文件。
数据规模与约定
对于所有数据,
1
≤
n
≤
5000
,
1
≤
a
i
≤
5000
1≤n≤5000,1≤a
i
≤5000。
本题采用捆绑评测,你只有通过了一个子任务中所有测试点才能得到该子任务的分数。
Subtask 1(10pts):
1
≤
n
≤
20
1≤n≤20。
Subtask 2(20pts):
1
≤
n
≤
80
1≤n≤80。
Subtask 3(10pts):
1
≤
n
≤
500
,
1
≤
a
i
≤
2
1≤n≤500,1≤a
i
≤2。
Subtask 4(20pts):
1
≤
n
≤
500
1≤n≤500。
Subtask 5(40pts):无特殊限制。
请针对以上问题详细注释上述代码,并带入样例
input = 6
2 1 1 1 1 2
详细模拟dp,pre,cnt,pos在每一次循环时的值,使用Markdown格式化你的解答
最新发布