题解: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;
}

浙公网安备 33010602011771号