【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}\)
即
第二个式子变换后得到\(\sum_{i=1}^ni(i!)(n-i)!C_{n+1}^{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;
}