R233727088 记录详情
编程语言 C++11 O2 全 WA
已经试过了不开O2:
R233732961 记录详情
编程语言 C++11 全 RE
下面是我写的code:
(为了以后给自己当模版已经加上了详细注释)
#include <bits/stdc++.h>
using namespace std;
const int INF = 1e9;
struct PrefixSum{ // 前缀和优化(封装)
vector<int> prefix; // prefix[i] 表示 origin[0] 到 origin[i-1] 的和
PrefixSum(const vector<int>& origin){
prefix.resize(origin.size()+1, 0);
int ind_cnt = 0;
for (int num : origin){
prefix[++ind_cnt] = prefix[ind_cnt-1]+num;
}
}
int get_sum(int l, int r) const { // @return : [l, r]的和
return prefix[r+1] - prefix[l];
}
};
int main(){
int N;
cin >> N;
vector<int> stones(N*2); // 扩大一倍模拟环形
for (int i=0; i<N; i++){
cin >> stones[i];
stones[i+N] = stones[i];
}
PrefixSum ps(stones);
// 定义状态 dp[i][j] 表示 合并从 [i,j] 石子的最优结果
// dp[i][j] 中 i==j 的初值应为 0 (一堆石子无法合并)
// dpmin初值应为 INF, dpmax初值应为 -INF (没有负值时 0 也可以)
vector< vector<int> > dpmin(N*2, vector<int>(N*2, INF));
vector< vector<int> > dpmax(N*2, vector<int>(N*2, 0));
int ansmin = INF, ansmax = 0; // 统计最终答案
for (int l=1; l<=N; l++){ // 枚举区间长度, 从 1 开始是为了赋初值
for (int i=0; i+l-1<N*2; i++){ // 枚举长度为 l 的所有区间起点
int j = i+l-1; // 得到区间终点, 完整区间[i,j] 长度为 l
if (i==j) dpmin[i][j] = 0; // dp[i][j] 中 i==j 的初值应为 0 (一堆石子无法合并)
else for (int k=i; k<j; k++){ // 枚举合并石子的区间[i,k]和[k+1,j]
dpmin[i][j] = min(dpmin[i][j], dpmin[i][k]+dpmin[k+1][j]+ps.get_sum(i,j));
dpmax[i][j] = max(dpmax[i][j], dpmax[i][k]+dpmax[k+1][j]+ps.get_sum(i,j));
}
if (l==N){ // 当区间长度为 N 时开始统计答案
if (dpmin[i][j] < ansmin) ansmin = dpmin[i][j];
if (dpmax[i][j] > ansmax) ansmax = dpmax[i][j];
}
}
}
cout << ansmin << "\n" << ansmax;
return 0;
}
先谢了!