首页 > 其他分享 >前缀和与组合数

前缀和与组合数

时间:2024-05-05 16:56:59浏览次数:21  
标签:&...& &... 前缀 组合 int hline ar

前缀和与组合数

一道题会涉及组合数一般有这么几种可能

  1. 题目公式里直接带了组合数。
  2. 题目和排列组合相关
  3. 特殊的高维前缀和

第一种第二种比较明显的和组合数相关联。
而第三种就和组合数的性质相关。
我认为多次前缀和会与组合数产生联系的本质是组合数的一个公式。
\(C(m,n)=C(m-1,n-1)+C(m-1,n)\)
(我记\(C(m,n)\)为从\(m\)个物品中取\(n\)个物品的组合)
从一般到特殊感受一下。

常数数组的高维前缀和

以常数为\(1\)举例,不同常数乘一个倍数即可。
记原数组ar,\(f^k(ar)\)为\(ar\)的\(k\)次前缀和

数值角度

\(\def\arraystretch{1.5} \begin{array}{|c|c|c|c|c|} \hline ar&1&1&1&...\\\hline f(ar)&1&2&3&...\\\hline f^2(ar)&1&3&6&...\\\hline f^3(ar)&1&4&10&...\\\hline f^4(ar)&1&5&15&...\\\hline ....&...&...&...&...\\\hline \end{array}\)
​记\(ar(x,y)\)为第\(x\)行,第\(y\)列的数。
有\(ar(x,y)=\sum^y_{i=1} ar(x-1,i)\)
前缀和式\(ar(x,y)=ar(x,y-1)+ar(x-1,y)\)
这和\(C(m,n)=C(m-1,n-1)+C(m-1,n)\)非常相似。事实上可以发现\(a(x,y)=C(x+y-2,y-1)\)当然,行列从\(0\)开始编号的话就恰好是\(ar(x,y)=C(x+y,y)\)。

路径

事实上,考虑从起点\((0,0)到(x,y)\),一次只能横坐标加一或者纵坐标加一,不同的路径数量,也是\(C(x+y,y)\),这个更好理解,就是一共走\(x+y\)步,然后挑选\(y\)步选择纵坐标加一。
\(C(m,n)=C(m-1,n-1)+C(m-1,n)\)在路径上的体现就是\((x,y)\)可以从\((x-1,y)\)或者\((x,y-1)\)直接到达。

任意数组高维前缀和

首先定义数组的加法:数组\(a,b,c\),\(\forall i\in N,a_i=b_i+c_i\)就记为\(a=b+c\)
前缀和的性质: $a=b+c \lrarr f ^ k(a)=f ^ k(b)+f ^ k(c) $ ,这说明原数组的前缀和的贡献是可加的。那我们直接按位计算前缀和贡献。
我们首先得知道某一位的\(1\)会产生什么样子的贡献。
\(\def\arraystretch{1.5} \begin{array}{|c|c|c|c|c|} \hline a&1&0&0&...\\\hline f(a)&1&1&1&...\\\hline f^2(a)&1&2&3&...\\\hline f^3(a)&1&3&6&...\\\hline f^4(a)&1&4&10&...\\\hline ....&...&...&...&...\\\hline \end{array}\)
规定从\(0\)开始编号
所以,记\(a_0\)位置为\((0,0)\),\(a_0\)对\([f^k(a)]_j\)的贡献是\(C(k+j,j)\)
同理的\(a_i\)对\([f^k(a)]_j\)的贡献是\(C(k+j-i,j-i)\)
那么\([f^k(a)] _j=\sum^j_{i=1} a_i\times C(k+j-i,j-i)\)

例题:Fenwick Tree

题目来源

https://codeforces.com/contest/1967/problem/C
codeforces round 942 div1 C

题目翻译

首先定义\(lowbit(i)\)为\(i\)转换为二进制,最小的为1的二进制位的权值。比如\(12=1100(B)=8+4,lowbit(12)=4\),\(lowbit(8)=8\)。
对于等长的数组\(s,a\)若满足$$s_k=(\sum^k_{i=k-lowbit(k)+1} a_i )mod\ 998244353$$则记为\(s=f(a)\)
\(f^k(a)=\begin{cases}a& if\ k=0 \\ f(f^{k-1}(a)) & if\ k\in N^* \end{cases}\)
给定数组长度\(n\)和\(k,b=f^k(a)\)求\(a\)

  • 数据范围:\(0\le a_i,b_i<998244353,1\le n\le 2\cdot 10^5,1\le k\le 10^9\)
  • 时空限制:\(3s,256MB\)

解法

先不考虑取模。
\(s_k=\sum^k_{i=k-lowbit(k)+1} a_i\)
这一部分其实是树状数组式的前缀和。
考虑\(a_i\)对\(s_k\)的贡献。
树状数组式的前缀和每一位如此提供贡献

void Modify(int x,int w){//a[x]=w
    while(x<=n){
        s[x]+=w;
        x+=lowbit(x);//lowbit(x)=x&-x;
    }
}

再看看\(a_1\)的贡献
\(\def\arraystretch{1.5} \begin{array}{|c|c|c|c|c|c|} \hline 下标&1&2&4&...&2^i\\\hline a&1(系数)&0&0&...&0\\\hline f(a)&1&1&1&...&1\\\hline f^2(a)&1&2&3&...&i+1\\\hline f^3(a)&1&3&6&...&C(i+2,2)\\\hline f^4(a)&1&4&10&...&C(i+3,3)\\\hline ....&...&...&...&...&...\\\hline f^k(a)&C(k-1,0)&C(k,1)&C(k+1,2)&...&C(k+i-1,k)\\\hline \end{array}\)
对于\(a_2,a_3\)啥的都是一样的
下标序列生成方式即\(x+=lowbit(x)\)
然后,对于\(s_i\),\(a_i\)的贡献系数只有\(1\),只要\(s_i\)把\(a_1\sim a_i-1\)的贡献全部减去,就能求得\(a_i\)。

复杂度

下标序列长度和\(O(n\log n)\),
预处理\(O(\log n)\)后,求组合数\(O(1)\)
时间复杂度\(O(n \log n)\)

代码

点我查看代码
#include<bits/stdc++.h> 
#define ll long long 
//#define int long long
#define mid ((l+r)>>1)
#define lson u<<1,l,mid
#define rson u<<1|1,mid+1,r
#define inf 0x3f3f3f3f 
typedef int LL;
const signed maxn=(signed)1e6+5;
const signed mod=998244353;
inline LL Read(){
	char ch=getchar();bool f=0;LL x=0;
	for(;!isdigit(ch);ch=getchar())if(ch=='-')f=1;
	for(;isdigit(ch);ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
	if(f==1)x=-x;return x;
}
int add(int a,int b){
	return ((a+=b)>=mod)?a-mod:a;
}
int mul(int x,int y){
	return (ll) x*y%mod;
}
int fpow(int a,int b){
	int ans=1;
	while(b){
		if(b&1) ans=mul(ans,a);
		a=mul(a,a);b>>=1;
	}
	return ans;
}
int inv[105],jc[105];
int Ck(int n){
	if(n<0) return 0;
	return mul(jc[n],inv[n]);
}
void init(){
	inv[0]=jc[0]=1;
	for(int i=1;i<=100;++i) jc[i]=mul(jc[i-1],i);
	inv[100]=fpow(jc[100],mod-2);
	for(int i=99;i;--i) inv[i]=mul(inv[i+1],i+1);
}
void jck(int n,int k){
	k%=mod;
	int mx=std::__lg(n);
	for(int i=1;i<=mx;++i) jc[i]=mul(jc[i-1],k+i-1);
}
int ar[maxn];
signed main()
	{	 
		LL T=Read();
		init();
		while (T--){
			int n=Read(),k=Read();
			for(int i=1;i<=n;++i) ar[i]=Read();
			jck(n,k);
			for(int i=1;i<=n;++i){
				int x=i+(i&-i),c=1;
				while(x<=n){
					//printf("ck(%d)=%d\n",c,Ck(c));
					ar[x]=add(ar[x],mod-mul(Ck(c),ar[i]));
					++c;
					x+=x&-x;
				}
			}
			for(int i=1;i<=n;++i) printf("%d%c",ar[i]," \n"[i==n]);
		}
		return 0;
	}	

标签:&...&,&...,前缀,组合,int,hline,ar
From: https://www.cnblogs.com/LOOP-0/p/18173620

相关文章

  • 51单片机程序框架之带顺序的组合按键触发
    /******************************************************************************此程序是依据吴坚鸿程序框架,在普中51A2单片机开发板上的程序练习程序目标:带顺序的按键组合键,按下后LED取反*****************************************************************************......
  • 2024-05-04:用go语言,给定一个起始索引为0的字符串s和一个整数k。 要进行分割操作,直到字
    2024-05-04:用go语言,给定一个起始索引为0的字符串s和一个整数k。要进行分割操作,直到字符串s为空:选择s的最长前缀,该前缀最多包含k个不同字符;删除该前缀,递增分割计数。如果有剩余字符,它们保持原来的顺序。在操作之前,可以修改字符串s中的一个字符为另一个小写英文字母。在最佳情......
  • 一些组合数学的证明
    广义二项式系数\(\dbinom{a}{n}=\dfrac{a^\underline{n}}{n!}\)证明:\(\dbinom{a}{n}=C_a^n=\dfrac{a!}{n!(a-n)!},\dfrac{a^\underline{n}}{n!}=\dfrac{\frac{a!}{(a-n)!}}{n!}=\dfrac{a!}{n!(a-n)!}\)对称公式\(\dbinom{n}{m}=\dbinom{n}{n-m}\)证明:......
  • 网课-组合数学学习笔记
    排列\[A_n^m=\dfrac{n!}{(n-m)!}\]组合\[\dbinom{n}{m}=\dfrac{n!}{(n-m)!}\]下降幂&上升幂\[\]二项式定理隔板法如果隔板法的每个间隔有下界(下界可以不同),可以先把下界从整体减去。P5520[yLOI2019]青原樱:可将树看作隔板。环排列\(n\)的长度,\(m\)种颜色。可以......
  • leetcode算法热题--字母异位词组合
    题目给你一个字符串数组,请你将字母异位词组合在一起。可以按任意顺序返回结果列表。字母异位词是由重新排列源单词的所有字母得到的一个新单词。示例1:输入:strs=["eat","tea","tan","ate","nat","bat"]输出:[["bat"],["nat","tan"],[&q......
  • Go语言系列——Go协程、信道(channel)、缓冲信道和工作池、Select、Mutex、结构体取代类
    文章目录21-Go协程Go协程是什么?Go协程相比于线程的优势如何启动一个Go协程?启动多个Go协程22-信道(channel)什么是信道?信道的声明通过信道进行发送和接收发送与接收默认是阻塞的信道的代码示例信道的另一个示例死锁单向信道关闭信道和使用forrange遍历信道23-缓冲信......
  • 主观赋权法、客观赋权法、组合赋权法、评价指标体系构建
    在科研领域,为了对某个研究主题进行深入的探讨和评估,我们往往需要构建一套科学合理的评价体系,并为其中的各项评价指标赋予相应的权重。比如,在评价一项新技术的性能时,我们可能会考虑其创新性、实用性、成本效益等多个维度。那么,如何为这些维度赋予合适的权重,以更准确地反映新技术的......
  • 前缀和的一些笔记
    左神课程笔记,前缀和笔记,(前缀和也是想双指针一样管理两个指针之间的区间的)前缀和(前i个数的和)个人理解,把前缀和当成两个指针,维护一个区间,例如i-1到i这两个双指针之间管理的线段上放着一个a[i-1],感觉差分也能这样理解,a[i-1]-a[i]之间放着一个差分值下标i结......
  • 从海量数据表中筛选符合不同条件组合的数据的SQL优化
    速度很慢的SQL脚本SETNOCOUNTON;DECLARE@snVARCHAR(200);DECLARE@nINT;DECLARE@sn_tabTABLE(idBIGINT,snVARCHAR(200));IFOBJECT_ID('tempdb..#tab_f1')ISNOTNULLDROPTABLE#tab_f1CREATETABLE#tab_f1(idBIGINT)CREATEINDEXidx_f1_id......
  • 组合计数思维题
    我们先研究一道数学题,请说出下面的方程有多少组正整数解:\(x_1+x_2+x_3+x_4=8\)。你可能已经想到了,这个问题其实等同于将\(8\)个苹果分成\(4\)组且每组至少\(1\)个苹果有多少种方案,因此该问题还可以进一步等价于在分隔\(8\)个苹果的\(7\)个空隙之间插入\(3\)......