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

作者: wjyyy 分类: 数学,组合数学,解题报告 发布时间: 2019-03-04 09:16

点击量:46

好玩的推式子

题目描述

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

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

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

输入格式:

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

输出格式:

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

输入输出样例

输入样例:

3
5 5
10 7
1145 14

输出样例:

32
968
763

数据范围与约定

对于 $latex 10\%$ 的数据,$latex t=1$,$latex n,k\le 1000$;
对于 $latex 30\%$ 的数据,$latex t=1$,$latex n,k\leq 1000000$;
对于 $latex 50\%$ 的数据,$latex t=1$,$latex n\le 10^{18},k\le 1000$;
对于 $latex 70\%$ 的数据,$latex t\le 100$,$latex n,k\le 10^{18}$;
对于 $latex 100\%$ 的数据,$latex t\le 100000$,$latex n,k\le 10^{18}$。

题解:

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

这个题求的是 $latex \sum_{i=0}^k\mathrm C_n^i\bmod 2333$。但是模数是 $latex 2333$ 因此可以考虑 Lucas 定理,即 $latex \mathrm C_n^m\% p=\mathrm C_{n\% p}^{m\% p}\mathrm C_{n/p}^{m/p}$。

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

而对于连续的 $latex i\in[2333k,2333k+2333)$ 它们的 $latex i/2333$ 是相同的,$latex i\%2333\in[0,2333)$,所以我们把需要求和的 $latex k$ 个数分成 $latex \left\lceil\frac{k}{2333}\right\rceil$ 段。其中前 $latex \left\lfloor\frac{k}{2333}\right\rfloor$ 段一定是完整的,因此可以表示为
$$
\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}
$$
对于加号后面的式子,$latex i/2333=0$,所以是对后面一个式子求和,因此可以用杨辉三角预处理,并求出前缀和,$latex O(1)$ 解决。

对于中间一个式子 $latex \sum_{i=0}^{2332}\mathrm C_{n\%2333}^i$ ,因为 $latex n\%2333<2333$ ,同理用杨辉三角。


$$
\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
$$
则原式为
$$
S\sum_{t=0}^{\left\lfloor\frac{k}{2333}\right\rfloor}\mathrm C_{n/2333}^t+A
$$

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

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

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;
}

说点什么

avatar
  Subscribe  
提醒
/* */