题面
题解
首先询问和原数列顺序无关,那么不妨把数列从大到小排序,仍记为 a i a_i ai。
那么题目就是给出 [ l , r ] [l,r] [l,r],问 a l , a l + 1 , ⋯ , a r a_l,a_{l+1},\cdots,a_r al,al+1,⋯,ar 中任取 k k k 个数,这 k k k 个数中最大值的期望。
由于这是等概率选择,每种情况出现的概率为 1 ( m k ) \dfrac{1}{\binom{m}{k}} (km)1(记 m = r − l + 1 m=r-l+1 m=r−l+1),所以我们只需计算每种情况的最大值之和即可。
容易想到直接枚举最大值为 a i a_i ai,那么剩余的 k − 1 k-1 k−1 个数就必须从 a i + 1 , a i + 2 , ⋯ , a r a_{i+1},a_{i+2},\cdots,a_r ai+1,ai+2,⋯,ar 里面选,方案数为 ( r − i k − 1 ) \dbinom{r-i}{k-1} (k−1r−i),故最大值为 a i a_i ai 的贡献为 a i × ( r − i k − 1 ) a_i\times \dbinom{r-i}{k-1} ai×(k−1r−i)。
所以总和即为 ∑ i = l r ( r − i k − 1 ) × a i \sum\limits_{i=l}^r \dbinom{r-i}{k-1}\times a_i i=l∑r(k−1r−i)×ai。
总时间复杂度 O ( n q ) O(nq) O(nq),上述部分都是比较容易想到的。
注意到 ∑ k ≤ 1 0 5 \sum k\leq 10^5 ∑k≤105,考虑把单次询问从 O ( n ) O(n) O(n) 向 O ( k ) O(k) O(k) 转换。
受到 subtask4 的启发,我们设
f
k
[
r
]
=
∑
i
=
1
r
(
r
−
i
k
−
1
)
×
a
i
f_k[r]=\sum\limits_{i=1}^r\dbinom{r-i}{k-1}\times a_i
fk[r]=i=1∑r(k−1r−i)×ai,那么每次询问
[
l
,
r
]
[l,r]
[l,r] 的答案即为:
f
k
[
r
]
−
∑
i
=
1
l
−
1
(
r
−
i
k
−
1
)
×
a
i
f_k[r]-\sum_{i=1}^{l-1}\dbinom{r-i}{k-1}\times a_i
fk[r]−i=1∑l−1(k−1r−i)×ai
试图也用
f
f
f 来表示
∑
i
=
1
l
−
1
(
r
−
i
k
−
1
)
×
a
i
\sum\limits_{i=1}^{l-1}\dbinom{r-i}{k-1}\times a_i
i=1∑l−1(k−1r−i)×ai:
∑
i
=
1
l
−
1
(
r
−
i
k
−
1
)
×
a
i
=
∑
i
=
1
l
−
1
∑
j
=
0
k
−
1
(
r
−
l
+
1
j
)
(
l
−
1
−
i
k
−
1
−
j
)
×
a
i
\begin{aligned} &\sum_{i=1}^{l-1}\dbinom{r-i}{k-1}\times a_i\\ =&\sum_{i=1}^{l-1}\sum_{j=0}^{k-1}\dbinom{r-l+1}{j}\dbinom{l-1-i}{k-1-j}\times a_i \end{aligned}
=i=1∑l−1(k−1r−i)×aii=1∑l−1j=0∑k−1(jr−l+1)(k−1−jl−1−i)×ai
(上面这步用到了范德蒙德卷积)
范德蒙德卷积:
∑ i = 0 k ( n i ) ( m k − i ) = ( n + m k ) \sum_{i=0}^{k}\dbinom{n}{i}\dbinom{m}{k-i}=\dbinom{n+m}{k} i=0∑k(in)(k−im)=(kn+m)
证明:从组合意义上即可理解,相当于从各有 n n n 个和 m m m 个的两堆中共取出 k k k 个球。
继续推:
∑
i
=
1
l
−
1
(
r
−
i
k
−
1
)
×
a
i
=
∑
i
=
1
l
−
1
∑
j
=
0
k
−
1
(
r
−
l
+
1
k
−
1
−
j
)
(
l
−
1
−
i
j
)
×
a
i
=
∑
i
=
1
l
−
1
∑
j
−
1
k
(
r
−
l
+
1
k
−
j
)
(
l
−
1
−
i
j
−
1
)
×
a
i
=
∑
j
−
1
k
(
r
−
l
+
1
k
−
j
)
∑
i
=
1
l
−
1
(
l
−
1
−
i
j
−
1
)
×
a
i
=
∑
j
−
1
k
(
r
−
l
+
1
k
−
j
)
f
j
[
l
−
1
]
\begin{aligned} &\sum_{i=1}^{l-1}\dbinom{r-i}{k-1}\times a_i\\ =&\sum_{i=1}^{l-1}\sum_{j=0}^{k-1}\dbinom{r-l+1}{k-1-j}\dbinom{l-1-i}{j}\times a_i\\ =&\sum_{i=1}^{l-1}\sum_{j-1}^{k}\dbinom{r-l+1}{k-j}\dbinom{l-1-i}{j-1}\times a_i\\ =&\sum_{j-1}^{k}\dbinom{r-l+1}{k-j}\sum_{i=1}^{l-1}\dbinom{l-1-i}{j-1}\times a_i\\ =&\sum_{j-1}^{k}\dbinom{r-l+1}{k-j}f_{j}[l-1]\\ \end{aligned}
====i=1∑l−1(k−1r−i)×aii=1∑l−1j=0∑k−1(k−1−jr−l+1)(jl−1−i)×aii=1∑l−1j−1∑k(k−jr−l+1)(j−1l−1−i)×aij−1∑k(k−jr−l+1)i=1∑l−1(j−1l−1−i)×aij−1∑k(k−jr−l+1)fj[l−1]
故每次询问
[
l
,
r
]
[l,r]
[l,r] 的答案就是:
f
k
[
r
]
−
∑
j
−
1
k
(
r
−
l
+
1
k
−
j
)
f
j
[
l
−
1
]
f_k[r]-\sum_{j-1}^{k}\dbinom{r-l+1}{k-j}f_{j}[l-1]
fk[r]−j−1∑k(k−jr−l+1)fj[l−1]
设
P
=
∑
k
P=\sum k
P=∑k,那么这样询问的总时间复杂度就是
O
(
q
+
P
)
O(q+P)
O(q+P) 的了,但是如果暴力
O
(
k
n
2
)
O(kn^2)
O(kn2) 预处理
f
f
f 的话我们是无法接受的。
考虑优化预处理的过程:
观察定义式
f
k
[
r
]
=
∑
i
=
1
r
(
r
−
i
k
−
1
)
×
a
i
f_k[r]=\sum\limits_{i=1}^r\dbinom{r-i}{k-1}\times a_i
fk[r]=i=1∑r(k−1r−i)×ai,由组合数递推公式
(
n
m
)
=
(
n
−
1
m
)
+
(
n
−
1
m
−
1
)
\dbinom{n}{m}=\dbinom{n-1}{m}+\dbinom{n-1}{m-1}
(mn)=(mn−1)+(m−1n−1) 可知:
f
k
[
r
]
=
∑
i
=
1
r
(
r
−
i
k
−
1
)
×
a
i
=
∑
i
=
1
r
[
(
r
−
i
−
1
k
−
1
)
+
(
r
−
i
−
1
k
−
2
)
]
×
a
i
=
f
k
[
r
−
1
]
+
f
k
−
1
[
r
−
1
]
\begin{aligned} f_k[r]&=\sum\limits_{i=1}^r\dbinom{r-i}{k-1}\times a_i\\ &=\sum\limits_{i=1}^r\left[\dbinom{r-i-1}{k-1}+\dbinom{r-i-1}{k-2}\right]\times a_i\\ &=f_{k}[r-1]+f_{k-1}[r-1] \end{aligned}
fk[r]=i=1∑r(k−1r−i)×ai=i=1∑r[(k−1r−i−1)+(k−2r−i−1)]×ai=fk[r−1]+fk−1[r−1]
于是预处理
f
f
f 的时间复杂度由
O
(
k
n
2
)
O(kn^2)
O(kn2) 降到了
O
(
k
n
)
O(kn)
O(kn),但这样还是不够。
我们考虑设置一个阈值 B B B:
-
当 k > B k> B k>B 时我们使用最开始说的暴力算法,这种算法的使用次数不会超过 P B \dfrac{P}{B} BP,总时间复杂度 O ( n P B ) O(\dfrac{nP}{B}) O(BnP);
-
当 k ≤ B k\leq B k≤B 时我们先 O ( n B ) O(nB) O(nB) 预处理出所有的 f k [ r ] f_k[r] fk[r],然后再 O ( q + P ) O(q+P) O(q+P) 询问。
总时间复杂度 O ( n B + n P B ) O(nB+\dfrac{nP}{B}) O(nB+BnP),注意到 n , P n,P n,P 同阶,取 B = P B=\sqrt P B=P 时有最优的时间复杂度 O ( n n ) O(n\sqrt n) O(nn)。
#include<bits/stdc++.h>
#define SN 320
#define N 100010
using namespace std;
namespace modular
{
const int mod=998244353;
inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
}using namespace modular;
inline int poww(int a,int b)
{
int ans=1;
while(b)
{
if(b&1) ans=mul(ans,a);
a=mul(a,a);
b>>=1;
}
return ans;
}
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^'0');
ch=getchar();
}
return x*f;
}
int n,q,B,a[N],b[N];
int fac[N],ifac[N];
int f[SN][N];
int C(int n,int m)
{
if(n<0||m<0||m>n) return 0;
return mul(mul(fac[n],ifac[m]),ifac[n-m]);
}
int solve1(int l,int r,int k)
{
int ans=0;
for(int i=l;i<=r;i++)
ans=add(ans,mul(C(r-i,k-1),a[i]));
return ans;
}
int solve2(int l,int r,int k)
{
int ans=f[k][r];
for(int j=1;j<=k;j++)
ans=dec(ans,mul(C(r-l+1,k-j),f[j][l-1]));
return ans;
}
int main()
{
n=read(),q=read(),B=sqrt(n);
for(int i=1;i<=n;i++) a[i]=read();
sort(a+1,a+n+1);
for(int i=1;i<=n;i++) b[i]=a[i];
reverse(a+1,a+n+1);
fac[0]=1;
for(int i=1;i<=100000;i++) fac[i]=mul(fac[i-1],i);
ifac[100000]=poww(fac[100000],mod-2);
for(int i=100000;i>=1;i--) ifac[i-1]=mul(ifac[i],i);
for(int r=1;r<=n;r++) f[1][r]=add(f[1][r-1],a[r]);
for(int k=2;k<=B;k++)
for(int r=1;r<=n;r++)
f[k][r]=add(f[k-1][r-1],f[k][r-1]);
while(q--)
{
int l=read(),r=read(),k=read();
l=lower_bound(b+1,b+n+1,l)-b;
r=upper_bound(b+1,b+n+1,r)-b-1;
swap(l,r);
l=n-l+1,r=n-r+1;
printf("%d ",r-l+1);
if(k>r-l+1)
{
puts("-1");
continue;
}
printf("%d\n",mul(k>B?solve1(l,r,k):solve2(l,r,k),poww(C(r-l+1,k),mod-2)));
}
return 0;
}
/*
7 3
83 74 100 89 95 79 72
90 100 3
80 89 1
70 79 2
*/