Loading

题解:CF2019B All Pairs Segments

All Pairs Segments

题意:

在数轴上有 \(n\) 个点,由小到大给定其坐标 \(x_i\),其中 \(i \in [1,n]\),每个点向其后面的所有点连线。

\(q\) 次询问,每次输入 \(k\),问被 \(k\) 条线段覆盖的点有多少个。

多组测试数据。

思路:

我们考虑分别计算每个点被多少条线段覆盖,再通过 map 统计被 \(k\) 条线段覆盖的点的个数即可。

对于编号为 \(i\) 的点:

  • 当其为线段左端点时,可以连出 \((n-i)\) 条线段,因为它后面有 \((n-i)\) 个点。
  • 当其为线段右端点时,可以连出 \((i-1)\) 条线段,因为它前面有 \((i-1)\) 个点。
  • 当其在线段中时,可以被 \((i-1) \times (n-i)\) 条线段覆盖,因为它前面的 \((i-1)\) 个点可以向后面的 \((n-i)\) 个点连线。

所以对于编号为 \(i\) 的点,共可以被 \((n-i)+(i-1)+(i-1) \times (n-i)\) 条线段覆盖。

对于编号 \(i\) 与编号 \(i+1\) 之间的点:

它们只能在线段中,可以被 \((i-1) \times (n-i)\) 条线段覆盖。


时间复杂度为 \(O(\sum n)\),可以通过本题。

注意:

由于 \(1 \le k \le 10^{18}\),所以要开 long long。

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll T, n, q, k;
ll x[100005];
map<ll, ll> m;
signed main() {
	cin >> T;
	while(T--) {
		m.clear();
		cin >> n >> q;
		for(int i=1; i<=n; i++) cin >> x[i];
		for(int i=1; i<=n; i++) {
			m[(n-i)+(i-1)+(i-1)*(n-i)]++; //统计点i答案 
			if(i+1<=n) m[i*(n-i)]+=(x[i+1]-x[i]-1); //统计i与i+1之间答案 
		}
		for(int i=1; i<=q; i++) {
			cin >> k;
			cout << m[k] << " ";
		}
		cout << "\n";
	}
	return 0;
}
posted @ 2024-10-11 15:21  Anins  阅读(47)  评论(0)    收藏  举报  来源