Problem C
Time Limit:1000MS Memory Limit:65536K
Total Submit:58 Accepted:13
Description
一日,code4101捡到一本《读入外挂》的武林秘籍。书上说,用getchar一个字符一个字符来手动实现整数的读入,比scanf直接读取一个整数要快上好多倍。
code4101怀疑有没有这么神奇,就想用读入外挂试试这道熟悉的题目,来一起AC吧。
考虑下图这个三角形,从第一行走到最后行,每一步都只能往下一行相邻的左边或右边移动,如何使路过的数字和最大。
如上面这个例子,行走路线:7->3->8->7->5,是和最大的走法,为30。
Input
输入数据的第一行为一个整数T,表示有T(0 < T < 5)组测试数据。
每个测试的第一行是一个整数R (1 <= R <= 3000),代表行数,接下来R行,第i行有i个正整数代表三角形每行的数值。
所有的单个元素值,及最终的和,均小于2 * 10^18。
Output
每个测试数据输出一行,为最大的和的数值。
Sample Input
1
5
7
3 8
8 1 0
2 7 4 4
4 100000000005 2 6 5
Sample Output
100000000030
Hint
因为数据量较大,请用getchar实现整数读入,代替scanf。
解法1:读入外挂模板+自底向上的dp:
#include <algorithm>
#include <cstdio>
#include <iostream>
using namespace std;
typedef unsigned long long LL;
LL a[3001][3001] = {};
//仅读正整数的读入外挂
template <typename T>
inline void read(T& x) {
char ch; while (!((((ch=getchar())>='0') && (ch <= '9')) || (ch == '-')));
x = ch-'0'; while (((ch=getchar())>='0') && (ch <= '9')) x = x*10+ch-'0';
}
int main() {
int n, i, j, now, T;
//freopen("in.txt","r",stdin);
read(T);
while (T--) {
read(n);
for(i=1;i<=n;i++)
{
for(j=1;j<=i;j++)
{
read(a[i][j]);
}
}
for(i=n-1;i>=1;i--)
{
for(j=1;j<=i;j++)
{
a[i][j]=a[i][j]+max(a[i+1][j],a[i+1][j+1]);
}
}
printf("%I64d\n",a[1][1]);
}
return 0;
}
解法二更加优化:来自学长的博客http://blog.youkuaiyun.com/code4101/article/details/40109333
#include <algorithm>
#include <cstdio>
#include <iostream>
using namespace std;
typedef unsigned long long LL;
//仅读正整数的读入外挂
template <typename T>
inline void read(T& x) {
char ch; while (!((((ch=getchar())>='0') && (ch <= '9')) || (ch == '-')));
x = ch-'0'; while (((ch=getchar())>='0') && (ch <= '9')) x = x*10+ch-'0';
}
int main() {
int n, i, j, now, T;
read(T);
while (T--) {
read(n);
LL a[2][3001] = {};
for (now = i = 1; i <= n; i++) {
now ^= 1;
for (j = 1; j <= i; j++) {
read(a[now][j]);
a[now][j] += max(a[now^1][j-1], a[now^1][j]);
}
}
cout << *max_element(&a[now][1], &a[now][n+1]) << "\n";
}
return 0;
}