loj 2038 / 洛谷 P4345 [SHOI2015] 超能粒子炮・改 题解【Lucas定理】

好玩的推式子

题目描述

曾经发明了脑洞治疗仪与超能粒子炮的发明家 SHTSC 又公开了他的新发明:超能粒子炮・改——一种可以发射威力更加强大的粒子流的神秘装置。

超能粒子炮・改相比超能粒子炮,在威力上有了本质的提升。它有两个参数 n n n k k k,它会向每个编号为 0 0 0 k k k(包含两端)的位置 i i i 发射威力为 C n i   m o d   2333 \mathrm{C}_n^i \bmod 2333 Cnimod2333 的粒子流。

现在 SHTSC 给出了他的超能粒子炮・改的参数,让你求出其发射的粒子流的威力之和除以 2333 2333 2333 所得的余数。

输入格式:

第一行一个整数 t t t 表示数据组数。
之后 t t t 行,每行两个整数 n n n k k k,含义如题面描述。

输出格式:

t t t 行,每行一个整数,表示其粒子流的威力之和模 2333 2333 2333 的值。

输入输出样例

输入样例:

3
5 5
10 7
1145 14

输出样例:

32
968
763

数据范围与约定

对于 10 % 10\% 10% 的数据, t = 1 t=1 t=1 n , k ≤ 1000 n,k\le 1000 n,k1000
对于 30 % 30\% 30% 的数据, t = 1 t=1 t=1 n , k ≤ 1000000 n,k\leq 1000000 n,k1000000
对于 50 % 50\% 50% 的数据, t = 1 t=1 t=1 n ≤ 1 0 18 , k ≤ 1000 n\le 10^{18},k\le 1000 n1018,k1000
对于 70 % 70\% 70% 的数据, t ≤ 100 t\le 100 t100 n , k ≤ 1 0 18 n,k\le 10^{18} n,k1018
对于 100 % 100\% 100% 的数据, t ≤ 100000 t\le 100000 t100000 n , k ≤ 1 0 18 n,k\le 10^{18} n,k1018

题解:

注:本文中所有的除法 / / /向下取整,所有的百分号 % \% % 都表示取模。

这个题求的是 ∑ i = 0 k C n i   m o d   2333 \sum_{i=0}^k\mathrm{C}_n^i\bmod 2333 i=0kCnimod2333。但是模数是 2333 2333 2333 因此可以考虑 Lucas 定理,即 C n m % p = C n % p m % p C n / p m / p \mathrm{C}_n^m\% p=\mathrm{C}_{n\% p}^{m\% p}\mathrm{C}_{n/p}^{m/p} Cnm%p=Cn%pm%pCn/pm/p

我们把上面的和式推导一下,则为
∑ i = 0 k C n / 2333 i / 2333 C n % 2333 i % 2333 \sum_{i=0}^k\mathrm{C}_{n/2333}^{i/2333}\mathrm{C}_{n\%2333}^{i\%2333} i=0kCn/2333i/2333Cn%2333i%2333
然后我们发现,整个过程中 n / 2333 n/2333 n/2333 n % 2333 n\% 2333 n%2333 是不变的。只需要关注 i / 2333 i/2333 i/2333 i % 2333 i\%2333 i%2333 的变化规律。

而对于连续的 i ∈ [ 2333 k , 2333 k + 2333 ) i\in[2333k,2333k+2333) i[2333k,2333k+2333) 它们的 i / 2333 i/2333 i/2333 是相同的, i % 2333 ∈ [ 0 , 2333 ) i\%2333\in[0,2333) i%2333[0,2333),所以我们把需要求和的 k k k 个数分成 ⌈ k 2333 ⌉ \left\lceil\frac{k}{2333}\right\rceil 2333k 段。其中前 ⌊ k 2333 ⌋ \left\lfloor\frac{k}{2333}\right\rfloor 2333k 段一定是完整的,因此可以表示为
∑ t = 0 ⌊ k 2333 ⌋ C n / 2333 t ∑ i = 0 2332 C n % 2333 i + ∑ i = k − k % 2333 k C n / 2333 i / 2333 C n % 2333 i % 2333 \sum_{t=0}^{\left\lfloor\frac{k}{2333}\right\rfloor}\mathrm{C}_{n/2333}^t\sum_{i=0}^{2332}\mathrm{C}_{n\%2333}^i+\sum_{i=k-k\%2333}^k\mathrm{C}_{n/2333}^{i/2333}\mathrm{C}_{n\%2333}^{i\%2333} t=02333kCn/2333ti=02332Cn%2333i+i=kk%2333kCn/2333i/2333Cn%2333i%2333
对于加号后面的式子, i / 2333 = 0 i/2333=0 i/2333=0,所以是对后面一个式子求和,因此可以用杨辉三角预处理,并求出前缀和, O ( 1 ) O(1) O(1) 解决。

对于中间一个式子 ∑ i = 0 2332 C n % 2333 i \sum_{i=0}^{2332}\mathrm{C}_{n\%2333}^i i=02332Cn%2333i ,因为 n % 2333 &lt; 2333 n\%2333&lt;2333 n%2333<2333 ,同理用杨辉三角。


∑ i = 0 2332 C n % 2333 i = S ,   ∑ i = k − k % 2333 k C n / 2333 i / 2333 C n % 2333 i % 2333 = A \sum_{i=0}^{2332}\mathrm{C}_{n\%2333}^i=S,\\\ \sum_{i=k-k\%2333}^k\mathrm{C}_{n/2333}^{i/2333}\mathrm{C}_{n\%2333}^{i\%2333}=A i=02332Cn%2333i=S, i=kk%2333kCn/2333i/2333Cn%2333i%2333=A
则原式为
S ∑ t = 0 ⌊ k 2333 ⌋ C n / 2333 t + A S\sum_{t=0}^{\left\lfloor\frac{k}{2333}\right\rfloor}\mathrm{C}_{n/2333}^t+A St=02333kCn/2333t+A

对于剩下的一个式子,又转化为了一个求和的子问题,因此我们递归解决。递归的边界是 k &lt; 2333 k&lt;2333 k<2333

因此可以在 233 3 2 + O ( t log ⁡ k ) 2333^2+O(t\log k) 23332+O(tlogk) 的时间复杂度内解决这个问题。

Code:

#include<cstdio>
#define ll long long
ll C[2333][2333];
ll calc(ll n,ll t)//0~t的C_n^t
{
    ll ans=0,p=n%2333;
    if(t/2333)
        ans=C[p][p]*calc(n/2333,t/2333-1)%2333;
    else
        return C[p][t%2333];
    ll a=n/2333,b=t/2333,tmp=1;
    while(a>=2333||b>=2333)
    {
        if(b%2333)
            tmp=tmp*(C[a%2333][b%2333]-C[a%2333][b%2333-1]+2333)%2333;
        a/=2333,b/=2333;
    }
    if(b)
        tmp=tmp*(C[a][b]-C[a][b-1]+2333)%2333;
    ans=(ans+C[p][t%2333]*tmp)%2333;
    return ans;
}
int main()
{
    C[0][0]=1;
    for(int i=1;i<=2332;++i)
    {
        C[i][0]=1;
        for(int j=1;j<=i;++j)
            C[i][j]=(C[i-1][j-1]+C[i-1][j])%2333;
    }
    for(int i=0;i<=2332;++i)
        for(int j=1;j<=2332;++j)
            C[i][j]=(C[i][j-1]+C[i][j])%2333;
    int T;
    ll n,k;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld%lld",&n,&k);
        printf("%lld\n",calc(n,k));
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值