题目链接:点击这里
题目大意:
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=0∑kCnimod2333
题目分析:
设
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=0∑kCni,p=2333 有:
F
(
n
,
k
)
=
∑
i
=
0
k
C
n
i
F(n,k)=\sum_{i=0}^kC_n^i
F(n,k)=i=0∑kCni
=
∑
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=0∑kCn/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=0∑p−1Cn%pi+Cn/p1i=0∑p−1Cn%pi+...+Cn/pk−1i=0∑p−1Cn%pi+Cn/pk/pi=0∑k%pCn%pi
前面
k
−
1
k-1
k−1 个是整块,最后一个不一定是完整的将其称之为余项,我们先考虑整块的处理,先将
∑
i
=
0
k
C
n
%
p
i
\sum\limits_{i=0}^kC_{n\%p}^i
i=0∑kCn%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=0∑p−1Cn%pij=0∑k/p−1Cn/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,p−1)F(n/p,k/p−1)
接下来我们考虑处理余项:
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=0∑k%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,p−1)F(n/p,k/p−1)+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,k−1)+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,p−1),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;
}