P4345 [SHOI2015]超能粒子炮·改(卢卡斯定理推式子)

题目链接:点击这里

题目大意:
t t t 组样例,每组样例给定 n , k n,k n,k 求:
∑ i = 0 k C n i m o d    2333 \sum_{i=0}^kC_n^i \mod 2333 i=0kCnimod2333

题目分析:
F ( n , k ) = ∑ i = 0 k C n i , p = 2333 F(n,k)=\sum\limits_{i=0}^kC_n^i,p=2333 F(n,k)=i=0kCni,p=2333 有:
F ( n , k ) = ∑ i = 0 k C n i F(n,k)=\sum_{i=0}^kC_n^i F(n,k)=i=0kCni
= ∑ i = 0 k C n / p i / p C n % p i % p =\sum_{i=0}^kC_{n/p}^{i/p}C_{n\%p}^{i\%p} =i=0kCn/pi/pCn%pi%p
对于这个式子我们观察 C n / p i / p C_{n/p}^{i/p} Cn/pi/p 发现这东西跟整除分块很像,我们可以对其进行分块对 C n / p i / p C_{n/p}^{i/p} Cn/pi/p 的每一个 i / p i/p i/p 进行合并:
= C n / p 0 ∑ i = 0 p − 1 C n % p i + C n / p 1 ∑ i = 0 p − 1 C n % p i + . . . + C n / p k − 1 ∑ i = 0 p − 1 C n % p i + C n / p k / p ∑ i = 0 k % p C n % p i =C_{n/p}^0\sum_{i=0}^{p-1}C_{n\%p}^i+C_{n/p}^1\sum_{i=0}^{p-1}C_{n\%p}^i+...+C_{n/p}^{k-1}\sum_{i=0}^{p-1}C_{n\%p}^i+C_{n/p}^{k/p}\sum_{i=0}^{k\%p}C_{n\%p}^i =Cn/p0i=0p1Cn%pi+Cn/p1i=0p1Cn%pi+...+Cn/pk1i=0p1Cn%pi+Cn/pk/pi=0k%pCn%pi
前面 k − 1 k-1 k1 个是整块,最后一个不一定是完整的将其称之为余项,我们先考虑整块的处理,先将 ∑ i = 0 k C n % p i \sum\limits_{i=0}^kC_{n\%p}^i i=0kCn%pi 提出了可得:
= ∑ i = 0 p − 1 C n % p i ∑ j = 0 k / p − 1 C n / p j =\sum_{i=0}^{p-1}C_{n\%p}^i\sum_{j=0}^{k/p-1}C_{n/p}^j =i=0p1Cn%pij=0k/p1Cn/pj
= F ( n % p , p − 1 ) F ( n / p , k / p − 1 ) =F(n\%p,p-1)F(n/p,k/p-1) =F(n%p,p1)F(n/p,k/p1)
接下来我们考虑处理余项:
C n / p k / p ∑ i = 0 k % p C n % p i C_{n/p}^{k/p}\sum_{i=0}^{k\%p}C_{n\%p}^i Cn/pk/pi=0k%pCn%pi
= C n / p k / p F ( n % p , k % p ) =C_{n/p}^{k/p}F(n\%p,k\%p) =Cn/pk/pF(n%p,k%p)
综上有:
F ( n , k ) = F ( n % p , p − 1 ) F ( n / p , k / p − 1 ) + C n / p k / p F ( n % p , k % p ) F(n,k)=F(n\%p,p-1)F(n/p,k/p-1)+C_{n/p}^{k/p}F(n\%p,k\%p) F(n,k)=F(n%p,p1)F(n/p,k/p1)+Cn/pk/pF(n%p,k%p)
对于 n < p n<p n<p k < p k<p k<p 的情况由 F ( n , k ) F(n,k) F(n,k) 的定义有:
F ( n , k ) = F ( n , k − 1 ) + C n k F(n,k)=F(n,k-1)+C_{n}^k F(n,k)=F(n,k1)+Cnk
边界为 F ( n , 0 ) = C n 0 = 1 F(n,0)=C_n^0=1 F(n,0)=Cn0=1
因此对于 F ( n % p , p − 1 ) , F ( n % p , k % p ) F(n\%p,p-1),F(n\%p,k\%p) F(n%p,p1),F(n%p,k%p) 我们可以打表求出,对于 C n / p k / p C_{n/p}^{k/p} Cn/pk/p 我们可以直接通过卢卡斯定理求出

时间复杂度为 O ( t l o g 2 n ) O(tlog^2n) O(tlog2n)

具体细节见代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
ll read()
{
	ll res = 0,flag = 1;
	char ch = getchar();
	while(ch<'0' || ch>'9')
	{
		if(ch == '-') flag = -1;
		ch = getchar();
	}
	while(ch>='0' && ch<='9')
	{
		res = (res<<3)+(res<<1)+(ch^48);//res*10+ch-'0';
		ch = getchar();
	}
	return res*flag;
}
const int maxn = 2333+5;
const int mod = 2333;
const double pi = acos(-1);
const double eps = 1e-8;
ll c[maxn][maxn],f[maxn][maxn];

ll lucas(ll n,ll m)
{
	if(!m) return 1;
	return lucas(n/mod,m/mod)*c[n%mod][m%mod]%mod;
}
ll F(ll n,ll k)
{
	if(k < 0) return 0;
	if(!n || !k) return 1;
	if(n < mod && k < mod) return f[n][k];
	return (F(n/mod,k/mod-1)*f[n%mod][mod-1]%mod+lucas(n/mod,k/mod)*f[n%mod][k%mod]%mod)%mod;
}
int main()
{
	ll t = read();
	c[0][0] = f[0][0] = 1;
	for(int i = 1;i < maxn;i++)
		c[i][i] = c[i][0] = f[i][0] = 1;
	for(int i = 1;i < maxn;i++)
		for(int j = 1;j < maxn;j++)
			c[i][j] = (c[i-1][j]+c[i-1][j-1])%mod;
	for(int i = 0;i < maxn;i++)
		for(int j = 1;j < maxn;j++)
			f[i][j] = (c[i][j]+f[i][j-1])%mod; 
	while(t--)
	{
		ll n = read(),k = read();
		printf("%lld\n",F(n,k));
	}
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值