【LOJ】小 Q 的序列

题目描述

\(\quad\) 传送门

题解


\(\quad \mathcal Solution \ \ \mathcal A:\)

\(\quad\) 毛夫的数学做法


\(\quad \mathcal Solution \ \ \mathcal B:\)

\(\quad\) 我们令:

\[b_i = a_i+i \]

\(\quad\) 我们考虑 \(b\) 的一个子集:

\[b_{t_1},b_{t_2},\cdot\cdot\cdot,b_{t_k} \to a_{t_1},a_{t_2},\cdot\cdot\cdot,a_{t_k} \]

\(\quad\) 我们可以知道其价值为:

\[\omega(b) = \prod\limits_{i}^k\left(a_{t_i}+i\right) = \prod\limits_{i}^k\left(b_{t_i}+i-t_i\right) \]

\(\quad\) 我们不妨尝试打开这个奇怪的东西,我们发现这个东西是由若干 \(b\) 乘法和若干 \(i-t_{i}\) 构成。

\(\quad\) 尝试寻找这个奇怪的东西的组合意义

\(\quad\) 发现,我们假设我们最后... 算了算了,根本说不清楚这个奇怪的组合意义,我还是举例子好了...

\(\quad\)\(n = 7\)

\(\quad\) 不妨令:

\[\{a_1,a_2,a_3,a_4,a_5,a_6,a_7\} = \{1,2,3,4,5,6,7\} \]

\(\quad\) 我们考虑某一个 \(k=3\) 元素子集:

\[\{a_2,a_4,a_6\}=\{2,4,6\},b_2=4,b_4=8,b_6 = 12 \]

\(\quad\) 我们考虑其中的一项:

\[b_2(-2)(-3) \]

\(\quad\) 考虑这个 \((-2)\times(-3) = 6\) 在干嘛。如果你的脑冻够大的话,你可以认为这是一个映射。

\(\quad\) 也就是对于一个 \(k\) 元素子集 \(b\),我们考虑其中选了 \(c\)\(b\),那么我们要做的就是把剩下的 \(k-c\) 个元素映射到某一个元素,具体来说,就是 \(b_{t_i}\)\(k-c\) 个元素 映射到没有在 \(b\) 中出现的元素的前 \(t_i\) 个中的某一个上面。 把不属于 \(b\) 的元素映射到自身。那 \(c\) 个元素带权值,并且映射到自身。其中权值为\(b_{t_i}\)的乘积。

\(\quad\) 也就是在上面的例子当中 \(n = 7,k = 3,c = 1\)。权值为 \(b_2 = 2\)

\(\quad\) 我们不妨把最后映射到同一个元素的元素合并起来。那么可以得到一个集合的划分,显然,可以证明这个划分对应了一种映射。那么集合拆分的 \(\text{Bell}\) 数不就是映射的数目吗?但是注意,我们这里是带符号\(\text{Bell}\) 数。符号为 \((-1)^{k-c}\)

\(\quad\) 我们可以这么认为 \(k-c = (n-c)-(n-k)\)

\(\quad\) 也就是说,我们可以认为这个是带符号的第二类斯特林数。

\(\quad\) 也就是:

\[B_n = \sum\limits_{k=0}^n(-1)^{n-k}\begin{Bmatrix}n \\ k \end{Bmatrix} \]

\(\quad\) 找到这个东西的生成函数的 \(\text{EGF}\)

\[B(x) = e^{1-e^{-x}} \]

\(\quad\) 然后大力 \(\text{exp}\) 就可以了。最后用分治 \(\text{NTT}\) 算出:

\[(x+b_1)(x+b_2)\cdot\cdot\cdot(x+b_n) \]

\(\quad\) 代码的话有手就行,这里放出主要代码...

int n,a[N] ; 
int f[N],g[N] ;
inline vector<int> solve(int l,int r){
	if(l == r) return (vector<int>){a[l],1} ;
	int mid = (l+r)>>1 ;
	vector<int> lans = solve(l,mid) ;
	vector<int> rans = solve(mid+1,r) ;
	int la = lans.size(),lb = rans.size() ;
	int len = la+lb-1,limit = 1 ;
	while(limit < len) limit <<= 1 ;
	for(int i = 0 ; i < la ; i++) f[i] = lans[i] ;
	for(int i = la ; i < limit ; i++) f[i] = 0 ; 
	for(int i = 0 ; i < lb ; i++) g[i] = rans[i] ; 
	for(int i = lb ; i < limit ; i++) g[i] = 0 ;
	Poly::calrev(limit) ;
	Poly::NTT(f,limit,1) ; Poly::NTT(g,limit,1) ;
	for(int i = 0 ; i < limit ; i++) f[i] = mul(f[i],g[i]) ;
	Poly::NTT(f,limit,-1) ;
	vector<int> ans ; ans.resize(len) ; 
	for(int i = 0 ; i < len ; i++) ans[i] = f[i] ;
	return ans ; 
}
int B[N],C[N] ; 
int main(){
	//freopen("in.txt","r",stdin) ;
	prework(4e5) ;
	cin >> n ;
	for(int i = 1 ; i <= n ; i++) scanf("%d",&a[i]),a[i] = add(a[i],i) ;
	vector<int> A = solve(1,n) ;
	for(int i = 1 ; i <= n ; i++) B[i] = (i&1) ? ifac[i] : sub(mod,ifac[i]) ;
	Poly::Exp(B,C,n+1) ;
	int ans = 0 ;
	for(int i = 0 ; i <= n ; i++) ans = add(ans,mul(C[i],mul(fac[i],A[i]))) ;
	cout << sub(ans,1) << endl ; 
	return 0 ; 
}

\(\quad\) 后话

\(\quad\) 对于这种组合意义可以说是奇怪的题目,代数似乎优势很大?不过似乎考场上难题似乎区分度不是很大?所以会不会无所谓?

\(\quad\) 还有一个问题就是,我的常数为什么这么大,\(\text{9000ms}\) 怒拿最劣解,我不会是被某人传染了吧...完了完了...


\(\quad \mathcal Solution \ \ \mathcal C:\)

\(\quad\) 现在回来看看自己以前的做法真的太辣鸡了,我们有个更好的做法。

\(\quad\) 讲一个常人能想到的 \(\text{dp}\) : \(f_{i,j}\) 代表前 \(i\) 个数字选出 \(j\) 个数字的时候的答案。

\(\quad\) 转移显然如下:

\[f_{i,j} = f_{i-1,j}+f_{i-1,j-1}(a_{i}+j) \]

\(\quad\) 很好!这个东西没法优化!

\(\quad\) 没办法,我们考虑转移它的定义。我们设 \(f_{i,j}\) 代表前 \(i\) 个数字选出 \(i-j\) 个数字的答案。

\(\quad\) 转移显然如下

\[f_{i,j} = f_{i-1,j-1}+f_{i-1,j}(a_{i}+i-j) = f_{i-1,j-1}+f_{i-1,j}(a_{i}+i)-jf_{i-1,j} \]

\(\quad\) 这个东西的组合意义比较自然

  • 不选第 \(i\) 个数字,代价 \(\times(a_i+i)\)

  • 选第 \(i\) 个数字,新建一个组,新建一个组方案数目显然为 \(\times 1\)

  • 选第 \(i\) 个数字,放到前 \(j\) 个组里面,方案数目显然为 \(j\),但是这里 \(\times (-j)\)

\(\quad\) 那么不选若干个数字的答案的生成函数可以直接分治 \(\text{NTT}\) 展开。

\(\quad\) 选若干个数的方案就是把若干个球放入盒子的方案数目,就是有符号罢了。很容易得到生成函数为 \(e^{1-e^{-x}}\)

\(\quad\) 把两个生成函数卷积起来就得到了答案。代码不变。


\(\quad\) 上面讲了三种不同的做法,思维的难度一个比一个低,但是想要找到万千解法当中优秀的做法却是十分困难的。很多时候开始思考的做法是复杂的,但是慢慢就能找到本质的做法,这也启示我们面对数学问题不能只会一种做法,只有融合思想,才能用最优雅的方案解出最复杂的题目...

posted @ 2020-11-12 18:50  蒟蒻tyy  阅读(121)  评论(4编辑  收藏  举报