计数,组合数

【JZOJ7280】序排速快

by AmanoKumiko

Description

定义一次泡冒为:

function bubblesort(A)
	for i = 1 → length(A) − 1 do
		if Ai > Ai+1 then
			swap(Ai,Ai+1)
		end if
	end for
end function

即, 从该数组的第一个位置开始, 设当前进行到的位置为\(i\) , 若\(Ai > Ai+1\)则交换。定义一次序排速快为:

function quicksort(A)
	if length(A) = 1 then
		return
	end if
	while no partition points exist in A do
		cnt ← cnt + length(A)
		bubblesort(A)
	end while
	divide A at all partition points; do quicksort at each piece
end function

即, 对于当前递归到的区间\([l, r]\), 定义一个位置$ i\(为分割点, 当且仅当\)∀x ∈ [l, i], y ∈ [i + 1, r], Ax < Ay\(。序排速快的过程是这样的, 对于当前的区间\)[l, r]$, 若该区间长度为 \(1\) , 直接返回;否则, 若该区间中存在分割点, 则找出所有分割点, 递归两两相邻分割点中的区间。即, 若当前递归区间为$ [l, r]$ , 分割点为 \(p1, p2, · · · , pk, ∀pi ∈ [l, r]\) 则递归\([l, p1], [p1 + 1, p2], . . . , [pk−1 + 1, pk], [pk + 1, r]\)。若不存在分割点, 则执行多次泡冒, 每一次泡冒将 \(cnt\) 的值加上$ r − l + 1$,直至出现分割点, 执行递归。给出两个正整数 \(L, R\) , 对所有的 \(n ∈ [L, R]\) 分别求出所有长度为$ n$ 的排列的 \(cnt\) 值之和对$ 998244353 $取模的结果。

Input

一行两个正整数\(L, R\),意义同题目描述

Output

为减少输出量,仅输出一个整数表示所有答案的异或和

Sample Input

2 8

Sample Output

920329

Data Constraint

对于 100% 的数据,\(2 ≤ L, R ≤ 10^7\)

Solution

(1)发现分割点的条件可以改成,对于\(i\)\([1,i]\)的数都已经在\(i\)左侧出现

(2)分割点\(i\)出现时,它左侧和右侧的分割点一定已经出现

(3)一个点的贡献就是它递归的层数

不妨对每个分割点\(i\)单独算贡献,设分割点\(i\)出现时间为\(t_i\),那么答案为\(\sum_{i=1}^nmax(t_i,t_{i-1})\)

由于一次冒泡可以使不在原来位置的点移动一格,设小于等于\(i\)的最大的数的位置为\(p_i\),那么移动次数为\(p_i-i\)

所以答案变成\(\sum_{i=1}^nmax(p_{i-1}-i+1,p_i-i)\)

分开算贡献:

对于\(t_i>=t_{i-1}\)\(\sum_{i=1}^n\sum_{j=i}^nC_{n-i}^{n-j}(n-j)!(j-1)!(j-i)\)\(i\)枚举分割点,\(j\)枚举\(p_i\),即\([i+1,n]\)选出一些放在\(j\)右边,剩下的放左边,同时\(j\)两边都是随便排列

对于\(t_{i-1}>t_i\),同理得\(\sum_{i=1}^n\sum_{j=i}^nC_{n-j}^{n-i}(n-j)!(j-1)!(j-i+1)(i-1)\),由于\(j\)此时放的是\([1,i-1]\)中的数,所以有\(i-1\)种选择

加起来得到\(\sum_{i=1}^n\sum_{j=i}^nC_{n-j}^{n-i}(j-1)!(n-j)!(ij-i^2+i-1)\)

\(\sum_{i=1}^n\sum_{j=i}^nC_{n-j}^{n-i}(j-1)!(n-j)!(-i^2+i-1)\)\(\sum_{i=1}^n\sum_{j=i}^nC_{n-j}^{n-i}(j-1)!(n-j)!ij\)

第一个式子变换后得到\(\sum_{i=1}^n(-i^2+i-1)(n-i)!(i-1)!C_{n}^{i}\)

\[n!\sum_{i=1}^n\frac{-i^2+i+1}{i} \]

第二个式子变换后得到\(\sum_{i=1}^ni(i!)(n-i)!C_{n+1}^{i+1}\)

\[(n+1)!\sum_{i=1}^n\frac{i}{i+1} \]

前缀和预处理一下随便算

Code

#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(long long i=a;i<=b;i++)
#define LL long long
#define N 10000010
#define mo 998244353

LL sum[N],fac[N],frac[N][2],L,R,inv[N];

int main(){
	freopen("tros.in","r",stdin);
	freopen("tros.out","w",stdout);
	fac[1]=inv[1]=1;
	F(i,1,N-10){
		inv[i+1]=mo-(mo/(i+1))*inv[mo%(i+1)]%mo;
		fac[i+1]=fac[i]*(i+1)%mo;
		frac[i][0]=(frac[i-1][0]+i*inv[i+1]%mo)%mo;
		frac[i][1]=(frac[i-1][1]+(-i*i%mo+i-1+mo)%mo*inv[i]%mo)%mo;
		sum[i]=(fac[i+1]*frac[i][0]%mo+fac[i]*frac[i][1]%mo)%mo^sum[i-1];
	}
	scanf("%lld%lld",&L,&R);
	printf("%lld",sum[R]^sum[L-1]);
	return 0;
}