隐藏
「JZOJ4746」树塔 - 棋盘动规 | Bill Yang's Blog

路终会有尽头,但视野总能看到更远的地方。

0%

「JZOJ4746」树塔 - 棋盘动规

题目大意

    相信大家都在长训班学过树塔问题,题目很简单求最大化一个三角形数塔从上往下走的路径和。走的规则是:$(i,j)$号点只能走向$(i+1,j)$或者$(i+1,j+1)$。如下图是一个数塔,映射到该数塔上行走的规则为:从左上角的点开始,向下走或向右下走直到最底层结束。
    $1$
    $3\,\,8$
    $2\,\,5\,\,0$
    $1\,\,4\,\,3\,\,8$
    $1\,\,4\,\,2\,\,5\,\,0$
    路径最大和是$1+8+5+4+4=22,1+8+5+3+5=22$或者$1+8+0+8+5=22$。
    小S觉得这个问题so easy。于是他提高了点难度,他每次ban掉一个点(即规定哪个点不能经过),然后询问你不走该点的最大路径和。
    当然他上一个询问被ban掉的点过一个询问会恢复(即每次他在原图的基础上ban掉一个点,而不是永久化的修改)。


题目分析

简单动规。

用$Up[i,j]$表示从$(1,1)$到达$(i,j)$的最大路径和,$Down[i,j]$表示从$(i,j)$到达$(n,i)$的最大路径和。
故我们可以使用$Up[i,j]+Down[i,j]-a[i,j]$表示经过$(i,j)$的最大路径和。

因为每行必须经过且只能经过一个结点,故每次ban掉一个结点,必定在该行另外新找一个结点使得权值和最大。

预处理行中$Up[i,j]+Down[i,j]-a[i,j]$的最大与次大,若ban掉最大则输出次大,否则输出最大。


代码

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
46
47
48
49
50
51
52
53
54
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;

inline const int Get_Int() {
int num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}

const int maxn=1005;
int n,q,a[maxn][maxn],Up[maxn][maxn],Down[maxn][maxn],Max[maxn],Second[maxn];

int main() {
n=Get_Int();
q=Get_Int();
for(int i=1; i<=n; i++)
for(int j=1; j<=i; j++)
a[i][j]=Get_Int();
for(int i=1; i<=n; i++)
for(int j=1; j<=i; j++)
Up[i][j]=max(Up[i-1][j-1],Up[i-1][j])+a[i][j];
for(int i=n; i>=1; i--)
for(int j=i; j>=1; j--)
Down[i][j]=max(Down[i+1][j],Down[i+1][j+1])+a[i][j];
for(int i=1; i<=n; i++)
for(int j=1; j<=i; j++)
if(Up[i][j]+Down[i][j]-a[i][j]>Max[i]) {
Second[i]=Max[i];
Max[i]=Up[i][j]+Down[i][j]-a[i][j];
} else Second[i]=max(Second[i],Up[i][j]+Down[i][j]-a[i][j]);
for(int i=1; i<=q; i++) {
int x=Get_Int(),y=Get_Int();
if(x==1&&y==1)puts("-1");
else if(Up[x][y]+Down[x][y]-a[x][y]==Max[x])printf("%d\n",Second[x]);
else printf("%d\n",Max[x]);
}
return 0;
}
姥爷们赏瓶冰阔落吧~