关于数据范围的问题
查看原帖
关于数据范围的问题
1288333
XURUIFAN楼主2025/7/31 11:47

本题中,质检员最高可能得到的检验结果

y=i=1m(j=liri[wjW]×j=liri[wjW]vj)y=\sum_{i=1}^m (\sum_{j=l_i}^{r_i}[w_j\ge W]\times \sum_{j=l_i}^{r_i}[w_j\ge W]v_j)

,其中,1n,m2×1051\le n,m\le2\times10^51lrn1\le l\le r\le n0<wi,vi1060<w_i,v_i\le10^6,如果所有的艾弗森括号内均取 11 (即 WW 的取值满足无论任何情况下均有 WwjW\le w_j),极限情况下可能出现

y=2×105×2×105×2×105×106y=2\times10^5\times2\times10^5\times2\times10^5\times10^6

::::info[上式解释] 其中:

  1. 第一个 2×1052\times10^5 表示 mm 的最大值,即 i=1m\sum_{i=1}^m
  2. 第二个 2×1052\times10^5 表示区间 [li,ri][l_i,r_i] 的长度(相当于是 [li,ri][l_i,r_i] 中满足 wjWw_j\ge W 的个数),即 j=liri[wjW]\sum_{j=l_i}^{r_i}[w_j\ge W]
  3. 后面的 2×105×1062\times10^5\times10^6 表示 vjv_j 的乘积和,即 j=liri[wjW]vj\sum_{j=l_i}^{r_i}[w_j\ge W]v_j。 :::: 这样一来,yy 的值将达到 8×10218\times10^{21},远超 long longunsigned long long 的存储范围,需要使用 __int128 ,但是经过测试,即使仅仅使用 long long 依然可以通过本题(记录)。 ::::info[code]
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef  pair<int, int> PII;
typedef  pair<ll, ll> PLL;
typedef  pair<int, ll> PIL;
#define mkp make_pair
#define F first
#define S second
#define psbk push_back
const int N = 201000;
const ll INF = 1ll << 60;
int n, m, w[N], v[N], l[N], r[N], c[N], d[N];
ll s;
inline ll solve(int W) {
	if (W == -1) return INF;
	if (W == 1000002) return -INF;
	for (int i = 1; i <= n; i++) {
		c[i] = (w[i] >= W);
		d[i] = (w[i] >= W) * v[i];
	}
	for (int i = 1; i <= n; i++) {
		c[i] += c[i - 1];
		d[i] += d[i - 1];
	}
	ll sum = 0;
	for (int i = 1; i <= m; i++) {
		sum += (c[r[i]] - c[l[i] - 1]) * (d[r[i]] - d[l[i] - 1]);
	}
	return sum;
}
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	cin >> n >> m >> s;
	for (int i = 1; i <= n; i++) cin >> w[i] >> v[i];
	for (int i = 1; i <= m; i++) cin >> l[i] >> r[i];
	int L = -1, R = 1000002;
	while (L + 1 < R) {
		int mid = L + ((R - L) >> 1);
		if (solve(mid) >= s) L = mid;
		else R = mid;
	}
	cout << min(abs(solve(L) - s), abs(solve(R) - s));
	return 0;
}

::::

这是否说明数据需要加强?亦或者数据范围需要进行一定的修改? 或者 cff 又拿脚出数据,就像你可以一直告诉指挥官“不可以,指挥官”然后获得 45 分。

::::info[] 事实上,当我使用以下代码测试时:

#include<bits/stdc++.h>
using namespace std;
//typedef long long ll;
typedef __int128 ll;
typedef unsigned long long ull;
typedef double db;
typedef  pair<int, int> PII;
typedef  pair<ll, ll> PLL;
typedef  pair<int, ll> PIL;
#define mkp make_pair
#define F first
#define S second
#define psbk push_back
const int N = 201000;
const ll INF = 1ll << 60;
int n, m, w[N], v[N], l[N], r[N], c[N], d[N];
ll s;
inline ll solve(int W) {
	if (W == -1) return INF;
	if (W == 1000002) return -INF;
	for (int i = 1; i <= n; i++) {
		c[i] = (w[i] >= W);
		d[i] = (w[i] >= W) * v[i];
	}
	for (int i = 1; i <= n; i++) {
		c[i] += c[i - 1];
		d[i] += d[i - 1];
	}
	ll sum = 0;
	for (int i = 1; i <= m; i++) {
		sum += (c[r[i]] - c[l[i] - 1]) * (d[r[i]] - d[l[i] - 1]);
	}
	return sum;
}
inline void print(ll a) {
	if (a < 10) {
		cout << ((int)a);
		return;
	}
	print(a / 10);
	a %= 10;
	cout << ((int)a);
}
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	n = m = 200000;
	for (int i = 1; i <= n; i++) w[i] = v[i] = 1000000;
	for (int i = 1; i <= m; i++) l[i] = 1, r[i] = n;
	print(solve(0));
//	cout << solve(0);
//	cin >> n >> m >> s;
//	for (int i = 1; i <= n; i++) cin >> w[i] >> v[i];
//	for (int i = 1; i <= m; i++) cin >> l[i] >> r[i];
//	int L = -1, R = 1000002;
//	while (L + 1 < R) {
//		int mid = L + ((R - L) >> 1);
//		if (solve(mid) >= s) L = mid;
//		else R = mid;
//	}
//	cout << min(abs(solve(L) - s), abs(solve(R) - s));
	return 0;
}

输出为 184549376-184549376 (我都不知道我这个输出还能出负数的)
而在第四行修改为typedef unsigned __int128 ll;后,输出为 340282366920938463463374389380389011456340282366920938463463374389380389011456

(作为参考,unsigned __int128 的最大值为 340282366920938463463374607431768211455340282366920938463463374607431768211455,比上数大 218051379199999218051379199999。) ::::

2025/7/31 11:47
加载中...