__int128
是占用 16 字节的变量类型。64 位 GCC/G++ 已支持,但不在 C/C++ 标准里,使用要加双下划线,不在 std
命名空间里,不属于标准库,使用时不需额外引入头文件。
因为它只是扩展了字节数,和高精度的实现不同,所以我把它成为“大精度”。 int128 的最大最小值分别为:
它的无符号类型 unsigned __int128
相应最大值(最小值是 0):
在支持的编译器里,它支持基本类型都具有的所有运算方式(模板库、库函数不是这部分),比如四则运算、类型转换、位运算、赋值。
它支持除了标准库里除了需要根据实际类型确定的所有模板函数。比如它能使用 std::max/min/sort/unique
等,不能使用 std::i/ostream
及其子类(大部分不支持的都是这种)。具体地,这些都不能直接用:
std::cin/cout/cerr/clog
标注输入/输出/错误流/日志流std::[i/o/io][s/f]stream
输入/输出字符串/文件流。
C 语言没有模板,当然也没有针对这种类型的函数。除非你愿意损失精度来强制转换成普通的类型(那还要 int128 干嘛)。
让标准库能支持这个类型也很简单,自己写个运算符重载就好。
using ll = __int128; // __int128_t
std::istream &operator>>(
std::istream &cin, ll &x) {
int a; cin >> a; x = a;
return cin;
}
std::ostream &operator<<(
std::ostream &cout, ll x) {
if (!x) cout << '0';
else if (x & ~((ll(1)<<60)-1))
cout << x/100000000 << x%100000000;
else cout << (long long)x;
return cout;
}
多数题目输入/输出不涉及大精度,只在运算过程涉及;少数在输出数据也是大精度。当输入也是大精度时也好办,读入一个字符串一位位赋值就好。这个板子不是重点,全局运算符重载才是核心。毕竟现在已经很少考高精度了,但运算符重载是 OI 和实际工程都用得到的东西。
Luogu P1005 有一个给定的
$m$ 行$n$ 列的矩阵。
- 每一次取数,从每行(行首或行尾)各取走一个,共
$n$ 个。$m$ 次后取完所有元素;- 在第
$i(\in[1,n])$ 次取数时,每取走一个$x$ ,会得到$2^ix$ 的分数;- 总得分为
$m$ 次取数得分之和。最大化总得分。
$1\le n,m\le 80$ ,$0\le a_{i,j}\le1000$。
每行都是独立的。设
边界:$f(i,i)=2^na_i$. 长度要不要加 1 减 1 视实现确定,取个特殊值就好了不想算。
#include <iostream>
using ll = __int128;
std::istream &operator>>(
std::istream &cin, ll &x) {
int a; cin >> a; x = a;
return cin;
}
std::ostream &operator<<(
std::ostream &cout, ll x) {
if (!x) cout << '0';
else if (x & ~((ll(1)<<60)-1))
cout << x/100000000 << x%100000000;
else cout << (long long)x;
return cout;
}
const int N = 88;
ll f[N][N], a[N], ans;
int n, m;
int main() {
std::cin >> m >> n;
while (m--) {
for (int i=0; i<n; i++) {
std::cin >> a[i];
f[i][i] = (a[i] << n);
}
ll w = (ll(1) << n-1);
for (int d=1; d<n; d++, w>>=1)
for (int i=0; i+d<n; i++)
f[i][i+d] = std::max(
f[i+1][i+d] + a[i]*w,
f[i][i+d-1] + a[i+d]*w);
ans += f[0][n-1];
}
std::cout << ans << '\n';
}