首页 > 其他分享 >【XSY4074】intervcl C(推式子,根号分类)

【XSY4074】intervcl C(推式子,根号分类)

时间:2022-10-31 07:35:54浏览次数:24  
标签:return dbinom int sum times intervcl XSY4074 复杂度 根号

题面

intervcl C

题解

首先询问和原数列顺序无关,那么不妨把数列从大到小排序,仍记为 \(a_i\)。

那么题目就是给出 \([l,r]\),问 \(a_l,a_{l+1},\cdots,a_r\) 中任取 \(k\) 个数,这 \(k\) 个数中最大值的期望。

由于这是等概率选择,每种情况出现的概率为 \(\dfrac{1}{\binom{m}{k}}\)(记 \(m=r-l+1\)),所以我们只需计算每种情况的最大值之和即可。

容易想到直接枚举最大值为 \(a_i\),那么剩余的 \(k-1\) 个数就必须从 \(a_{i+1},a_{i+2},\cdots,a_r\) 里面选,方案数为 \(\dbinom{r-i}{k-1}\),故最大值为 \(a_i\) 的贡献为 \(a_i\times \dbinom{r-i}{k-1}\)。

所以总和即为 \(\sum\limits_{i=l}^r \dbinom{r-i}{k-1}\times a_i\)。

总时间复杂度 \(O(nq)\),上述部分都是比较容易想到的。

注意到 \(\sum k\leq 10^5\),考虑把单次询问从 \(O(n)\) 向 \(O(k)\) 转换。

受到 subtask4 的启发,我们设 \(f_k[r]=\sum\limits_{i=1}^r\dbinom{r-i}{k-1}\times a_i\),那么每次询问 \([l,r]\) 的答案即为:

\[f_k[r]-\sum_{i=1}^{l-1}\dbinom{r-i}{k-1}\times a_i \]

试图也用 \(f\) 来表示 \(\sum\limits_{i=1}^{l-1}\dbinom{r-i}{k-1}\times 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} \]

(上面这步用到了范德蒙德卷积)

范德蒙德卷积:

\[\sum_{i=0}^{k}\dbinom{n}{i}\dbinom{m}{k-i}=\dbinom{n+m}{k} \]

证明:从组合意义上即可理解,相当于从各有 \(n\) 个和 \(m\) 个的两堆中共取出 \(k\) 个球。

继续推:

\[\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} \]

故每次询问 \([l,r]\) 的答案就是:

\[f_k[r]-\sum_{j-1}^{k}\dbinom{r-l+1}{k-j}f_{j}[l-1] \]

设 \(P=\sum k\),那么这样询问的总时间复杂度就是 \(O(q+P)\) 的了,但是如果暴力 \(O(kn^2)\) 预处理 \(f\) 的话我们是无法接受的。

考虑优化预处理的过程:

观察定义式 \(f_k[r]=\sum\limits_{i=1}^r\dbinom{r-i}{k-1}\times a_i\),由组合数递推公式 \(\dbinom{n}{m}=\dbinom{n-1}{m}+\dbinom{n-1}{m-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} \]

于是预处理 \(f\) 的时间复杂度由 \(O(kn^2)\) 降到了 \(O(kn)\),但这样还是不够。

我们考虑设置一个阈值 \(B\):

  • 当 \(k> B\) 时我们使用最开始说的暴力算法,这种算法的使用次数不会超过 \(\dfrac{P}{B}\),总时间复杂度 \(O(\dfrac{nP}{B})\);

  • 当 \(k\leq B\) 时我们先 \(O(nB)\) 预处理出所有的 \(f_k[r]\),然后再 \(O(q+P)\) 询问。

总时间复杂度 \(O(nB+\dfrac{nP}{B})\),注意到 \(n,P\) 同阶,取 \(B=\sqrt P\) 时有最优的时间复杂度 \(O(n\sqrt n)\)。

#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
*/

标签:return,dbinom,int,sum,times,intervcl,XSY4074,复杂度,根号
From: https://www.cnblogs.com/ez-lcw/p/16842964.html

相关文章

  • 【XSY3988】安静(数学,根号分类讨论)
    题面安静题解首先题目的条件可以看作是:如果当前时刻\(X\)模\(T_i\)为\(j\),那么就会得到\(f_i(j)\)的贡献。构造一个答案时刻\(X\),使得总贡献最大,求总贡献的最大......
  • 【XSY2423】跳蚤(根号分治)
    题面题解神奇的分类讨论。首先注意到每次所有跳蚤都只会往右跳,也就是说只要某一只跳蚤跳出了\(\max(r_i)\)它就不会再有贡献了。(和火神的鱼类似)令\(R=\max(r_i)......
  • 根号分治简单笔记 | P3396 哈希冲突
    简要题意你需要维护一个长度为\(n\)的序列\(v\),支持:Axy求整个序列中,所有模\(x\)为\(y\)的下标的元素的值,即:\[\sum_{i=0}^{\lfloor(n-y)\divx\rfloor}v_{ix......
  • 三角形ABC中,AB=AC,AD=2,BD*CD=2倍根号3,求AC长度?
    2022年10月23日11点09分END......
  • Snowy Mountain (找规律来贪心+ 多源特殊bfs+根号n)
    题目大意:给定一棵 nn 个点的树,其中每个点可能是黑色或白色。一个点的高度定义为其距离最近黑色节点的距离。你初始在 ii 号节点上,势能为 00,可以做以下两种操作:......
  • 根号算法学习记录
    根号算法专题分块基础根号平衡对于两个不同方面的复杂度,直接做的话一个很小,一个很大,我们用根号使得两者复杂度同阶级以降低总复杂度。这个叫根号平衡。一个典型的应用......
  • 洛谷 P8572【暴力】【根号分治】
    根号分治。需要进行分类讨论:当\(n\lek\)的时候,可以进行暴力\(\#1\):暴力求出数组所有区间的最大值。(需要使用前缀和)否则,可以使用一个叫做“记忆化”的鬼玩意。如......
  • 【luogu CF1553F】Pairwise Modulo(树状数组)(根号分治)
    PairwiseModulo题目链接:luoguCF1553F题目大意给你一个序列,对于每个前缀,要你求两两互相取模的结果的和。思路考虑新加入一个数增加的答案。那就是加两个部分:\(\sum......
  • 基于systemgenerator的根号计算
    一、系统设计仿真结果以及硬件资源估计(用于复制到你的那个txt文件中去即可。)顶层框图: 整个系统的结构如下所示: 进入内部模块则有: 其主要由三大部分组成: 第一部分:输入信......
  • 2022牛客OI赛前集训营-提高组(第一场) 奇怪的函数 根号很好用
    奇怪的函数考虑暴力,每次查询\(O(n)\)扫所有操作,修改\(O(1)\)这启发我们平衡复杂度,考虑分块。观察题目性质,可以发现,经过若干次操作后得到的结果一定是一个关于\(x\)的分......