社区讨论

求问此题在 dp 转移过程中为什么不会爆 long long

P4983忘情参与者 1已保存回复 1

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
1 条
当前快照
1 份
快照标识符
@mhjhj60l
此快照首次捕获于
2025/11/04 02:40
4 个月前
此快照最后确认于
2025/11/04 02:40
4 个月前
查看原帖
先放代码:
CPP
#include <bits/stdc++.h>
#define il inline
#define int __int128

using namespace std;

il int read() {
	int x = 0; char ch = getchar(); bool t = 0;
	while (ch < '0' || ch > '9') {t ^= ch == '-'; ch = getchar();}
	while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
	return t ? -x : x;
}
char stk[50];
il void write(int x, bool t = 1) {
	int top = 0;
	x < 0 ? putchar('-'), x = -x : 0;
	do {stk[++top] = x % 10 | 48; x /= 10;} while(x);
	while(top) putchar(stk[top--]);
	t ? putchar('\n') : putchar(' ');
}
const int N = 1e5 + 10;
int n, m, a[N], s[N];
int f[N], g[N];
int mid;
il int y(int j) {return -f[j] - s[j] * s[j] + 2 * s[j];}
il int k(int i) {return 2 * s[i];}
il int x(int j) {return -s[j];}
il int b(int i) {return -f[i] + s[i] * s[i] + 2 * s[i] + 1 - mid;}
il double slope(int i, int j) {
	return 1.0 * (y(i) - y(j)) / (x(i) - x(j));
}
int q[N], head, tail;
il bool check(int mid) {
	f[0] = 0;
	head = 1, tail = 0;
	q[++tail] = 0;
	for (int i = 1; i <= n; i++) {
		while (head < tail && slope(q[head], q[head + 1]) < k(i)) head++;
		f[i] = -y(q[head]) + k(i) * x(q[head]) + s[i] * s[i] + 2 * s[i] + 1 - mid;
		g[i] = g[q[head]] + 1;
		while (head < tail && slope(q[tail - 1], q[tail]) > slope(q[tail], i)) tail--;
		q[++tail] = i;
//		if (f[i] < -(1ll << 63) || f[i] > (1ll << 63) - 1) {
//			putchar('!' );
//			write(f[i]);
//			exit(0);
//		}
	}
	return g[n] <= m;
}
signed main() {
//	freopen("1.in", "r", stdin);
//	freopen("1.out", "w", stdout);
	n = read(), m = read();
	for (int i = 1; i <= n; i++) {
		a[i] = read();
		s[i] = s[i - 1] + a[i];
	}
	int l = -1e17, r = 0, ans = 0;
	while (l <= r) {
		mid = (l + r) >> 1;
		if (check(mid)) {
			ans = mid;
			l = mid + 1;
		} else {
			r = mid - 1;
		}
	}
	check(ans);
	write(f[n] + m * ans);
	
	return 0;
}
上面这篇代码是可以 AC 的。
关注到,wqs 二分每次转移时都会额外加上 mid-mid,而此题的二分下界应取到 1016-10^{16}。而转移可以至多进行 m105m \le 10^5 次。
所以我认为上限的话 mid-mid 会被累加 10510^5 次,这样的话 105×(1016)10^5 \times (-10^{16}) 实际上是会爆 long long 的。
我的问题就是:为什么这个题的转移不会爆 long long?或者说会爆 long long 所以需要开 __int128
跪求大佬解答。

回复

1 条回复,欢迎继续交流。

正在加载回复...