BZOJ4403 序列统计

该文章描述了一种计算在给定范围内长度和元素值都满足特定条件的单调不降序列数量的算法。利用Lucas定理,可以有效地求解这类问题,通过对组合数的计算和转换来得到答案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

给定三个正整数N、L和R,统计长度在1到N之间,元素大小都在L到R之间的单调不降序列的数量。输出答案对 1 0 6 + 3 10^6+3 106+3取模的结果。

输入

输入第一行包含一个整数T,表示数据组数。
第2到第T+1行每行包含三个整数N、L和R,N、L和R的意义如题所述。
1≤N,L,R≤10^9,1≤T≤100,输入数据保证L≤R。

输出

输出包含T行,每行有一个数字,表示你所求出的答案对 1 0 6 + 3 10^6+3 106+3取模的结果。

样例输入

2
1 4 5
2 4 5

样例输出

2
5

题解

前置知识:lucas定理

在区间 [ l , r ] [l,r] [l,r]中长度为 n n n的单调不降序列的数量,即 C r − l + 1 + n − 1 n = C r − l + n n C_{r-l+1+n-1}^n=C_{r-l+n}^n Crl+1+n1n=Crl+nn个。

题意即求 ∑ i = 1 n C r − l + i i \sum\limits_{i=1}^nC_{r-l+i}^i i=1nCrl+ii。因为 C n m = C n n − m C_n^m=C_n^{n-m} Cnm=Cnnm,所以

∑ i = 1 n C r − l + i i = ∑ i = 1 n C r − l + i r − l \sum\limits_{i=1}^nC_{r-l+i}^i=\sum\limits_{i=1}^nC_{r-l+i}^{r-l} i=1nCrl+ii=i=1nCrl+irl

又因为

∑ i = m n C i m = C n + 1 m + 1 \sum\limits_{i=m}^nC_i^m=C_{n+1}^{m+1} i=mnCim=Cn+1m+1

所以

∑ i = 1 n C r − l + i r − l = ( ∑ i = 0 n C r − l + i r − l ) − 1 = C r − l + n + 1 r − l + 1 − 1 = C r − l + n + 1 n − 1 \sum\limits_{i=1}^nC_{r-l+i}^{r-l}=(\sum\limits_{i=0}^nC_{r-l+i}^{r-l})-1=C_{r-l+n+1}^{r-l+1}-1=C_{r-l+n+1}^n-1 i=1nCrl+irl=(i=0nCrl+irl)1=Crl+n+1rl+11=Crl+n+1n1

C r − l + n + 1 n − 1 C_{r-l+n+1}^n-1 Crl+n+1n1即为答案,用lucas定理求出即可。

code

#include<bits/stdc++.h>
using namespace std;
int n;
long long vt=1,x,y,ans=0,a[15],b[15];
void exgcd(long long c,long long d){
	if(d==0){
		x=1;y=0;
		return;
	}
	exgcd(d,c%d);
	long long t=x;x=y;y=t-c/d*y;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld%lld",&a[i],&b[i]);
		vt=vt*a[i];
	}
	for(int i=1;i<=n;i++){
		exgcd(vt/a[i],a[i]);
		x=(x%a[i]+a[i])%a[i];
		ans=(ans+vt/a[i]*b[i]*x%vt)%vt;
	}
	printf("%lld",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值