1. 程式人生 > >[BZOJ4591]超能粒子炮

[BZOJ4591]超能粒子炮

nom CA 粒子 const sca lucas定理 typedef 計算 std

預備知識是lucas定理:$\begin{align*}\binom{n}{k}\equiv\binom{\left\lfloor\frac np\right\rfloor}{\left\lfloor\frac kp\right\rfloor}\binom{n\%p}{k\%p}(\bmod p)\end{align*}$,這裏的$p$是質數

證明如下

首先,由費馬小定理得$(1+x)^p\equiv1+x\equiv1+x^p(\bmod p)$

$\begin{align*}(1+x)^n&\equiv(1+x)^{p\left\lfloor\frac np\right\rfloor}(1+x)^{n\%p}\\&\equiv\left(1+x^p\right)^{\left\lfloor\frac np\right\rfloor}(1+x)^{n\%p}\\&\equiv\left(\sum\limits_{i=0}^{\left\lfloor\frac np\right\rfloor}\binom{\left\lfloor\frac np\right\rfloor}ix^{pi}\right)\left(\sum\limits_{i=0}^{n\%p}\binom{n\%p}ix^i\right)\end{align*}$

對兩邊取$x^k$的系數,立得$\begin{align*}\binom{n}{k}\equiv\binom{\left\lfloor\frac np\right\rfloor}{\left\lfloor\frac kp\right\rfloor}\binom{n\%p}{k\%p}(\bmod p)\end{align*}$

再看這題,直接推公式

$\begin{align*}f(n,k)&\equiv\sum\limits_{i=0}^k\binom ni\\&\equiv\sum\limits_{i=0}^{\left\lfloor\frac kp\right\rfloor p-1}\binom{\left\lfloor\frac np\right\rfloor}{\left\lfloor\frac ip\right\rfloor}\binom{n\%p}{i\%p}+\sum\limits_{i=\left\lfloor\frac kp\right\rfloor p}^k\binom{\left\lfloor\frac np\right\rfloor}{\left\lfloor\frac ip\right\rfloor}\binom{n\%p}{i\%p}\\&\equiv\left(\sum\limits_{x=0}^{\left\lfloor\frac kp\right\rfloor-1}\binom{\left\lfloor\frac np\right\rfloor}x\right)\left(\sum\limits_{y=0}^{p-1}\binom{n\%p}y\right)+\binom{\left\lfloor\frac np\right\rfloor}{\left\lfloor\frac kp\right\rfloor}\sum\limits_{i=0}^{k\%p}\binom{n\%p}i\\&\equiv f\left(\left\lfloor\frac np\right\rfloor,\left\lfloor\frac kp\right\rfloor-1\right)f(n\%p,p-1)+\binom{\left\lfloor\frac np\right\rfloor}{\left\lfloor\frac kp\right\rfloor}f(n\%p,k\%p)\end{align*}$

所以預處理上下標在$[0,2332]$內的組合數,每次詢問遞歸計算即可

#include<stdio.h>
typedef long long ll;
const int p=2333;
int C[p][p],S[p][p];
int get(ll n,ll k){
	if(n<k)return 0;
	if(n<p&&k<p)return C[n][k];
	return get(n/p,k/p)*get(n%p,k%p)%p;
}
int f(ll n,ll k){
	if(k<0)return 0;
	return(f(n/p,k/p-1)*S[n%p][p-1]+get(n/p,k/p)*S[n%p][k%p])%p;
}
int main(){
	int i,j,t;
	ll n,k;
	C[0][0]=1;
	for(i=1;i<p;i++){
		C[i][0]=1;
		for(j=1;j<p;j++)C[i][j]=(C[i-1][j]+C[i-1][j-1])%p;
	}
	for(i=0;i<p;i++){
		S[i][0]=1;
		for(j=1;j<p;j++)S[i][j]=(S[i][j-1]+C[i][j])%p;
	}
	scanf("%d",&t);
	while(t--){
		scanf("%lld%lld",&n,&k);
		printf("%d\n",f(n,k));
	}
}

[BZOJ4591]超能粒子炮