[BZOJ] 4403: 序列统计

本文探讨了一道算法题目,通过将问题转化为组合数学中的盒子小球问题,利用组合恒等式和Lucas定理求解。文章详细介绍了如何计算特定条件下序列的数量,包括使用递归公式、组合数计算及模运算。

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

可以填的数有\(R-L+1\)个,可以填的位置有\(n\)
注意到,一旦每种数有几个确定了,最终的序列也就确定了
因此我们只需要确定每种数填几个,这就是一个盒子小球问题
不妨记\(C=R-L+1\)
\(n\)个球,划分到\(R-L+1\)个盒子中,盒子可以空的方案数
\[ \binom{n+C-1}{C-1} \]
再求一个前缀和
\[ \sum_{i=1}^n\binom{i+C-1}{C-1} \]
由组合恒等式
\[ \sum_{i=0}^n\binom{i+m}{m}=\binom{m+n+1}{m+1} \]
所以
\[ ans=\binom{n+C}{C} \]
1e6+3是素数,Lucas爆算即可

#include<algorithm>
#include<iostream>
#include<cstdio>
#define int long long
using namespace std;

const int MOD = 1e6+3;

inline int rd(){
  int ret=0;char c;
  while(c=getchar(),!isdigit(c));
  while(isdigit(c))ret=ret*10+c-'0',c=getchar();
  return ret;
}
#define space() putchar(' ')
#define nextline() putchar('\n')
void _(int x){if(!x)return;_(x/10);putchar('0'+x%10);}
void out(int x){if(!x)putchar('0');_(x);}


const int MAXN = 1000005;
const int UP = 1e6+2;

int n,m,L,R;

int fac[MAXN],inv[MAXN];
int qpow(int x,int y){
  int ret=1ll;
  while(y){
    if(y&1)(ret*=x)%=MOD;
    (x*=x)%=MOD;
    y>>=1ll;
  }
  return ret;
}
int C(int x,int y){if(y>x) return 0;return (((fac[x]*inv[y])%MOD)*inv[x-y])%MOD;}
int lucas(int x,int y){
  if(y>x)return 0;
  if(!x||!y) return 0;
  return x<MOD?C(x,y):lucas(x/MOD,y/MOD)*C(x%MOD,y%MOD)%MOD;
}

void solve(){
  n=rd();L=rd();R=rd();
  m=R-L;
  cout<<(lucas(n+m+1,m+1)-1+MOD)%MOD<<endl;
}

signed main(){
  fac[0]=1;inv[0]=1;
  for(int i=1;i<=UP;i++)fac[i]=(fac[i-1]*i)%MOD;
  inv[UP]=qpow(fac[UP],MOD-2);
  for(int i=UP-1;i;i--)inv[i]=(inv[i+1]*(i+1))%MOD;
  for(int T=rd();T;T--)solve();
  return 0;
}

转载于:https://www.cnblogs.com/ghostcai/p/9807956.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值