B
题目链接
发现有些题解写的不太容易理解,代码没讲清楚,所以有了下面这篇题解
分析:
根据题目可以得知区间如下
[
x
1
,
x
2
]
,
[
x
1
,
x
3
]
,
[
x
1
,
x
4
]
…
[
x
1
,
x
n
]
[x_1, x_2], [x_1, x_3], [x_1, x_4]\ldots[x_1, x_n]
[x1,x2],[x1,x3],[x1,x4]…[x1,xn]
[
x
2
,
x
3
]
,
[
x
2
,
x
4
]
,
[
x
2
,
x
5
]
…
[
x
2
,
x
n
]
[x_2, x_3], [x_2, x_4], [x_2, x_5]\ldots[x_2, x_n]
[x2,x3],[x2,x4],[x2,x5]…[x2,xn]
.
.
.
[
x
n
−
2
,
x
n
−
1
]
,
[
x
n
−
2
,
x
n
]
[x_{n-2},x_{n-1}], [x_{n-2},x_n]
[xn−2,xn−1],[xn−2,xn]
[
x
n
−
1
,
x
n
]
[x_{n-1},x_n]
[xn−1,xn]
对于
k
k
k这个点,要求它被那些区间所包括,分两种情况来看:
-
如果 k k k是某一个 x i x_i xi,那么有如下的情况
- k k k是一些区间的左端点的情况,那么有几个 x i x_i xi以它为左端点呢,就是 n − i n-i n−i个,分别是 { x i + 1 , x i + 2 , x i + 3 , … , x n x_{i+1},x_{i+2}, x_{i+3},\ldots, x_n xi+1,xi+2,xi+3,…,xn} ; ; ;
- 有几个点
x
i
x_i
xi以
k
k
k为右端点呢,就是
i
−
1
i-1
i−1个,分别是
{ x 1 , x 2 , x 3 , … , x i − 1 x_{1},x_{2}, x_{3},\ldots, x_{i-1} x1,x2,x3,…,xi−1} - 有几个区间包含
k
k
k这个点呢,就是
(
i
−
1
)
∗
(
n
−
i
)
(i-1)*(n-i)
(i−1)∗(n−i)个,分别是左端点:{
x
1
,
x
2
,
x
3
,
…
,
x
i
−
1
x_{1},x_{2}, x_{3},\ldots, x_{i-1}
x1,x2,x3,…,xi−1},和右端点:
{ x i + 1 , x i + 2 , x i + 3 , … , x n x_{i+1},x_{i+2}, x_{i+3},\ldots, x_n xi+1,xi+2,xi+3,…,xn}
-
如果 k k k是在 ( x i , x i + 1 ) (x_i, x_{i+1}) (xi,xi+1)这个开区里的一个点,那么有几个区间包含它呢?可以看有几个左端点,有几个右端点,这些左端点右端点两两配对会包括 k k k这个点,即 i i i个左端点,分别是{ x 1 , x 2 , x 3 , … , x i x_1, x_2, x_3,\ldots, x_i x1,x2,x3,…,xi},和 ( n − i ) (n - i) (n−i)个右端点,分别是{ x i + 1 , x i + 2 , x i + 3 , … , x n x_{i+1}, x_{i+2}, x_{i+3},\ldots, x_n xi+1,xi+2,xi+3,…,xn},两两配对,那么 k k k这个点就被 i ∗ ( n − i ) i*(n-i) i∗(n−i)这么多个区间包括
所以可以设 m x m_x mx为恰好被 x x x个区间包括的点有几个。在刚才讲的第一种情况就是在求 m i − 1 + n − i + ( i − 1 ) ∗ ( n − 1 ) m_{i-1+n-i+(i-1)*(n-1)} mi−1+n−i+(i−1)∗(n−1),可以简化成 m n − 1 + ( i − 1 ) ∗ ( n − 1 ) m_{n-1+(i-1)*(n-1)} mn−1+(i−1)∗(n−1),有些题解直接告诉你简化后的,没有一步步告诉你怎么来的。刚才讲的第二种情况就是在求 m i ∗ ( n − i ) m_{i*(n-i)} mi∗(n−i),于是可以来预处理 m m m,其余看代码
#include <bits/stdc++.h>
#define int long long // 不开long long见祖宗
using namespace std;
signed main() {
int _ = 1;
cin >> _;
while (_ -- ) {
int n, q;
cin >> n >> q; // 输入
vector<int> x(n + 1);
map<int, int> m; // m[x]表示恰好被x个区间所包括的点有多少个
for (int i = 1; i <= n; i++) cin >> x[i]; // 输入
// 预处理
for (int i = 1; i <= n; i++) {
m[i - 1 + n - i + (i - 1) * (n - i)] ++ ; // 第一种情况
if (i < n) m[i * (n - i)] += (x[i + 1] - x[i] - 1); // 第二种情况
}
while (q -- ) {
int k;
cin >> k; // 询问
cout << m[k] << ' '; // 输出
}
cout << '\n'; // 输出
}
return 0;
}
Codeforces Round 975 (Div. 2) B题题解
2854

被折叠的 条评论
为什么被折叠?



