在线评测:
http://codevs.cn/problem/1166/
(为了便于书写,以下内容不含高精度,包括AC代码,(简洁,更易理解))
整体思路:
还是感觉记忆化搜索比较好写,就写了记忆化搜索。每次考虑一个区间,先去掉首元素和先去掉尾元素的情况。然后记忆化搜下去下去就好
预处理只要处理处每一个数最后被选的得分是多少即可
失误之处:
开始只用dpij是否为0判断这个区间有没有被搜过,但是后来发现,有些区间他本身就是0.。。你这么一直搜就re了,,,,,
后来改用vis。然而由于是多case,,,然后vis每次没初始化为0,,,就固定输出第一组,,,QAQ
对了,,还是那个傻逼错误,,调用dfs的时候又习惯性写成直接访问dp数组,,,,
别光想着把数组什么开成int64,,,dfs返回值也得开longlong,,,
体会心得:
平时应该复习一下高精度什么。。。
多case什么的多看看初始化的周不周到。。。。
别光想着把数组什么开成int64,,,dfs返回值也得开longlong,,,要全面。。
AC代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using
namespace
std;
int
n,m;
bool
vis[100][100];
long
long
ans,dp[100][100],sz[100];
long
long
ksm(
int
x,
int
k)
{
if
(k == 1)
return
x;
long
long
tp = ksm(x,k >> 1);
if
(k & 1)
return
tp * tp * x;
return
tp * tp;
}
long
long
dfs(
int
s,
int
t)
{
if
(vis[s][t])
return
dp[s][t];
vis[s][t] =
true
;
return
dp[s][t] = max(dfs(s+1,t) + sz[s] * ksm(2,m - t + s), dfs(s,t - 1) + sz[t] * ksm(2,m - t + s));
}
void
init()
{
memset
(dp,0,
sizeof
(dp));
memset
(vis,0,
sizeof
(vis));
for
(
int
i = 1;i <= m;i++)
dp[i][i] = sz[i] * ksm(2,m),vis[i][i] =
true
;
}
int
main()
{
scanf
(
"%d%d"
,&n,&m);
for
(
int
i = 1;i <= n;i++)
{
for
(
int
j = 1;j <= m;j++)
{
scanf
(
"%lld"
,&sz[j]);
}
init();
long
long
tp = 0;
tp = dfs(1,m);
ans += tp;
}
printf
(
"%lld\n"
,ans);
return
0;
}
|