洛谷P4345 [SHOI2015]超能粒子炮·改

题目链接: [ S H O I 2015 ] 超 能 粒 子 炮 ⋅ 改 \rm [SHOI2015]超能粒子炮·改 [SHOI2015]
感谢 V e n u s \rm Venus Venus 神仙帮助完成 LaTeX \LaTeX LATEX 公式


显然题目让我们求的是 [ ∑ i = 0 k ( n i ) ] % p \rm \left[\sum\limits_{i=0}^k\binom ni\right]\%p [i=0k(in)]%p 的值,其中 p = 2333 \rm p=2333 p=2333
sum ⁡ ( n , k ) = [ ∑ i = 0 k ( n i ) ] % p \rm \operatorname{sum}(n,k)=\left[\sum\limits_{i=0}^k\binom ni\right]\%p sum(n,k)=[i=0k(in)]%p
然后我们开始推式子(大波 LaTeX \LaTeX LATEX 公式警告):

sum ⁡ ( n , k ) = [ ∑ i = 0 k ( n i ) ] % p (为保证界面美观,以下省略%p) = ∑ i = 0 k ( n / p i / p ) ( n % p i % p ) (卢卡斯定理) = [ ∑ i = 0 p − 1 ( n / p 0 ) ( n % p i ) ] + [ ∑ i = 0 p − 1 ( n / p 1 ) ( n % p i ) ] + ⋯   + [ ∑ i = 0 p − 1 ( n / p k / p − 1 ) ( n % p i ) ] + [ ∑ i = 0 k % p ( n / p k / p ) ( n % p i ) ] (整除分块) = [ ( n / p 0 ) ∑ i = 0 p − 1 ( n % p i ) ] + [ ( n / p 1 ) ∑ i = 0 p − 1 ( n % p i ) ] + ⋯   + [ ( n / p k / p − 1 ) ∑ i = 0 p − 1 ( n % p i ) ] + [ ( n / p k / p ) ∑ i = 0 k % p ( n % p i ) ] = [ ∑ i = 0 p − 1 ( n % p i ) ] × [ ∑ j = 0 k / p − 1 ( n / p j ) ] + ( n / p k / p ) ∑ i = 0 k % p ( n % p i ) \begin{aligned} \rm \operatorname{sum}(n,k) & =\rm \left[ \sum_{i=0}^k\binom ni \right] \%p \quad\color{#66ccff}\textbf{(为保证界面美观,以下省略\%p)}\\ & =\rm \sum_{i=0}^k\binom{n/p}{i/p}\binom{n\%p}{i\%p} \color{#66ccff}\textbf{(卢卡斯定理)}\\ & =\rm \left[ \sum_{i=0}^{p-1}\binom{n/p}0\binom{n\%p}i\right] +\left[\sum_{i=0}^{p-1}\binom{n/p}1\binom{n\%p}i\right]+\cdots \\ & \rm \quad\ +\left[\sum_{i=0}^{p-1}\binom{n/p}{k/p-1} \binom{n\%p}i\right] +\left[\sum_{i=0}^{k\% p}\binom{n/p}{k/p}\binom{n\%p}i \right] \color{#66ccff}\textbf{(整除分块)}\\ & =\rm \left[\binom{n/p}0\sum_{i=0}^{p-1}\binom{n\%p}i\right] +\left[\binom{n/p}1\sum_{i=0}^{p-1}\binom{n\%p}i\right]+\cdots \\ & \rm\quad\ +\left[\binom{n/p}{k/p-1}\sum_{i=0}^{p-1}\binom{n\%p}i\right] +\left[\binom{n/p}{k/p}\sum_{i=0}^{k\%p}\binom{n\%p}i\right] \\ & =\rm \left[\sum_{i=0}^{p-1}\binom{n\%p}i\right] \times\left[\sum_{j=0}^{k/p-1}\binom{n/p}j\right] +\binom{n/p}{k/p}\sum_{i=0}^{k\%p}\binom{n\%p}i \end{aligned} sum(n,k)=[i=0k(in)]%p(为保证界面美观,以下省略%p=i=0k(i/pn/p)(i%pn%p)(卢卡斯定理)=[i=0p1(0n/p)(in%p)]+[i=0p1(1n/p)(in%p)]+ +[i=0p1(k/p1n/p)(in%p)]+i=0k%p(k/pn/p)(in%p)(整除分块)=[(0n/p)i=0p1(in%p)]+[(1n/p)i=0p1(in%p)]+ +[(k/p1n/p)i=0p1(in%p)]+(k/pn/p)i=0k%p(in%p)=[i=0p1(in%p)]×j=0k/p1(jn/p)+(k/pn/p)i=0k%p(in%p)

再套用一下 sum ⁡ \operatorname{sum} sum 的定义就有:
sum ⁡ ( n , k ) = [ sum ⁡ ( n % p , p − 1 ) × sum ⁡ ( n / p , k / p − 1 ) + ( n / p k / p ) sum ⁡ ( n % p , k % p ) ] % p \rm \operatorname{sum}(n,k)= \left [\operatorname{sum}(n\%p,p-1) \times\operatorname{sum}(n/p,k/p-1) +\binom{n/p}{k/p}\operatorname{sum}(n\%p,k\%p)\right] \%p sum(n,k)=[sum(n%p,p1)×sum(n/p,k/p1)+(k/pn/p)sum(n%p,k%p)]%p

化简完毕。那么各部分如何处理呢?

sum ⁡ ( n % p , p − 1 ) , sum ⁡ ( n % p , k % p ) 的 参 数 都 小 于 p , 可 以 预 处 理 出 来 ; 2333 是 质 数 , 所 以 ( n / p k / p ) 显 然 可 以 用 L u c a s 搞 出 来 ; sum ⁡ ( n / p , k / p − 1 ) 可 以 递 归 求 解 。 \begin{aligned} & \rm \operatorname{sum}(n\%p,p-1),\operatorname{sum}(n\%p,k\%p) 的参数都小于 p ,可以预处理出来; \\ & \rm 2333是质数,所以\binom{n/p}{k/p}显然可以用Lucas搞出来; \\ & \rm \operatorname{sum}(n/p,k/p-1)可以递归求解。 \end{aligned} sum(n%p,p1),sum(n%p,k%p)p2333(k/pn/p)Lucassum(n/p,k/p1)

代码

#include<cstdio>
#include<cctype>
#define getc (l==r&&(r=(l=f)+fread(f,1,1<<21,stdin),l==r)?EOF:*l++)
//fread优化快读
typedef long long ll;
const int p=2333;

char f[1<<21],*l=f,*r=f;
inline ll read() { //快读
	ll x=0; char ch=getc;
	while (!isdigit(ch)) ch=getc;
	while (isdigit(ch)) { x=x*10+(ch^48); ch=getc; }
	return x;
}

int c[p][p],s[p][p];
void work() {
	//杨辉三角预处理组合数
	for (int i=0; i<p; ++i) c[i][0]=c[i][i]=s[i][0]=1;
	for (int i=1; i<p; ++i)
		for (int j=1; j<i; ++j)
			c[i][j]=(c[i-1][j]+c[i-1][j-1])%p;
	//前缀和预处理
	for (int i=0; i<p; ++i)
		for (int j=1; j<p; ++j)
			s[i][j]=(s[i][j-1]+c[i][j])%p;
}
int C(ll n,ll m) {
	return m?C(n/p,m/p)*c[n%p][m%p]%p:1; //卢卡斯
}
int S(ll n,ll m) {
	if (!n||!m) return 1;
	if (n<p&&m<p) return s[n][m];
	int ans=(m>=p?s[n%p][p-1]*S(n/p,m/p-1)%p:0);
	(n/p>=m/p)&&(ans+=C(n/p,m/p)*s[n%p][m%p]%p);
	return ans%p;
}

int main() {
	work();
	int T=read();
	while (T--) {
		ll n=read(),m=read();
		printf("%d\n",S(n,m));
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值