【省选模拟赛】序排速快(数学,递推)

题面

在这里插入图片描述
2 ≤ L ≤ R ≤ 1 0 7 2\leq L\leq R\leq10^7 2LR107

题解

题目相当于求“泡冒”的总时间,我们对于每个数字求贡献。

我们发现,每次“泡冒”,一个数 p i p_i pi 前面比它大的数如果有,必定减少一个,否则令后面最后一个比 p i p_i pi 小的数为 p j p_j pj [ i , j ) [i,j) [i,j) 区间内大于等于 p i p_i pi 的数将减少一个(包括自己)。

所以,我们可以先计算 p i p_i pi 前面比它大的数个数的总贡献,再计算 [ i , j ) [i,j) [i,j) 内的贡献。

前者是老经典问题了,递推式很简单,令 f ( x ) f(x) f(x) 表示长度为 x x x 的排列的答案,那么枚举最后一个数的逆序对个数:
f ( x ) = f ( x − 1 ) ⋅ x + x ! ⋅ x ( x − 1 ) 2 f ( 1 ) = 0 f(x)=f(x-1)\cdot x+x!\cdot\frac{x(x-1)}{2}\\ f(1)=0 f(x)=f(x1)x+x!2x(x1)f(1)=0

对于后者,我们可以考虑枚举 [ i , j ) [i,j) [i,j) 内大于等于 p i p_i pi 的数的贡献。若存在 i ≤ k , j > k i\leq k,j>k ik,j>k 满足 p j < p i ≤ p k p_j<p_i\leq p_k pj<pipk ,那么 p k p_k pk 就对 p i p_i pi 产生一次贡献。对于这个问题,之前「枚举最后一个数的贡献」的转移方法不太适用,我们需要换一个思路——枚举最大的数的贡献。我们令 g ( x ) g(x) g(x) 表示长度为 x x x 的排列的答案,枚举最大的数 p k = x p_k=x pk=x 的位置,计算左边每个数的贡献。对于 k k k ,贡献是 1,对于左边的 k − 1 k-1 k1 个数,有 x − k x − k + 1 \frac{x-k}{x-k+1} xk+1xk 的概率产生贡献,因此
g ( x ) = g ( x − 1 ) ⋅ x + ( x − 1 ) ! ( x − 1 + ∑ i = 1 x − 1 i i + 1 ⋅ ( x − i − 1 ) ) = g ( x − 1 ) ⋅ x + ( x − 1 ) ! ( x − 1 + ∑ i = 1 x − 1 ( i x i + 1 − i ) ) = g ( x − 1 ) ⋅ x + ( x − 1 ) ! ( x − 1 + x ∑ i = 1 x − 1 ( 1 − 1 i + 1 ) − ∑ i = 1 x − 1 i ) = g ( x − 1 ) ⋅ x + ( x − 1 ) ! ( x − 1 + x ( x − 1 ) − ∑ i = 1 x − 1 1 i + 1 − ∑ i = 1 x − 1 i ) = g ( x − 1 ) ⋅ x + ( x − 1 ) ! ( x − 1 + x ( x − 1 ) 2 − ∑ i = 1 x − 1 1 i + 1 ) g(x)=g(x-1)\cdot x+(x-1)!(x-1+\sum_{i=1}^{x-1}\frac{i}{i+1}\cdot(x-i-1))\\ =g(x-1)\cdot x+(x-1)!(x-1+\sum_{i=1}^{x-1}(\frac{ix}{i+1}-i))\\ =g(x-1)\cdot x+(x-1)!(x-1+x\sum_{i=1}^{x-1}(1-\frac{1}{i+1})-\sum_{i=1}^{x-1}i)\\ =g(x-1)\cdot x+(x-1)!(x-1+x(x-1)-\sum_{i=1}^{x-1}\frac{1}{i+1}-\sum_{i=1}^{x-1}i)\\ =g(x-1)\cdot x+(x-1)!(x-1+\frac{x(x-1)}{2}-\sum_{i=1}^{x-1}\frac{1}{i+1})\\ g(x)=g(x1)x+(x1)!(x1+i=1x1i+1i(xi1))=g(x1)x+(x1)!(x1+i=1x1(i+1ixi))=g(x1)x+(x1)!(x1+xi=1x1(1i+11)i=1x1i)=g(x1)x+(x1)!(x1+x(x1)i=1x1i+11i=1x1i)=g(x1)x+(x1)!(x1+2x(x1)i=1x1i+11)

右边的 ∑ 1 i + 1 \sum \frac{1}{i+1} i+11 可以预处理出来,于是这道题就做完了,时间复杂度 O ( R ) O(R) O(R) ,答案是
⨁ i = L R ( f ( i ) + g ( i ) m o d    998244353 ) \bigoplus_{i=L}^R (f(i)+g(i)\mod 998244353) i=LR(f(i)+g(i)mod998244353)

CODE

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<random>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 10000005
#define LL long long
#define ULL unsigned long long
#define ENDL putchar('\n')
#define DB double
#define lowbit(x) (-(x) & (x))
#define FI first
#define SE second
int xchar() {
	static const int maxn = 1000000;
	static char b[maxn];
	static int pos = 0,len = 0;
	if(pos == len) pos = 0,len = fread(b,1,maxn,stdin);
	if(pos == len) return -1;
	return b[pos ++];
}
//#define getchar() xchar()
LL read() {
	LL f = 1,x = 0;int s = getchar();
	while(s < '0' || s > '9') {if(s<0)return -1;if(s=='-')f=-f;s = getchar();}
	while(s >= '0' && s <= '9') {x = (x<<1) + (x<<3) + (s^48);s = getchar();}
	return f*x;
}
void putpos(LL x) {if(!x)return ;putpos(x/10);putchar((x%10)^48);}
void putnum(LL x) {
	if(!x) {putchar('0');return ;}
	if(x<0) putchar('-'),x = -x;
	return putpos(x);
}
void AIput(LL x,int c) {putnum(x);putchar(c);}

const int MOD = 998244353;
const int inv2 = (MOD+1)/2,inv3 = (MOD+1)/3,inv4 = inv2*1ll*inv2%MOD,inv6 = inv2*1ll*inv3%MOD;
int n,m,s,o,k;
int fac[MAXN],dp[MAXN],dp2[MAXN],invs[MAXN];
int main() {
	freopen("tros.in","r",stdin);
	freopen("tros.out","w",stdout);
	n = read();m = read();
	fac[0] = fac[1] = 1; invs[0] = invs[1] = 1;
	for(int i = 2;i <= m+1;i ++) {
		fac[i] = fac[i-1] *1ll* i % MOD;
		invs[i] = (MOD-invs[MOD%i]) *1ll* (MOD/i) % MOD;
	}
	for(int i = 2;i <= m+1;i ++) {
		(invs[i] += invs[i-1]) %= MOD;
	}
	dp[1] = 0;
	for(int i = 2;i <= m;i ++) {
		dp[i] = (dp[i-1]*1ll*i%MOD + ((i-1)*1ll*i/2)%MOD*fac[i-1]%MOD) % MOD;
		dp2[i] = (dp2[i-1]*1ll*i%MOD + (i-1+i*1ll*(i-1)/2+MOD-(invs[i]+MOD-invs[1])%MOD*1ll*i%MOD)%MOD*1ll*fac[i-1]%MOD) % MOD;
	}
	int ans = 0;
	for(int i = n;i <= m;i ++) ans ^= (dp[i]+dp2[i])%MOD;
	AIput(ans,'\n'); 
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值