P4345 [SHOI2015]超能粒子炮·改 题解

此题对于50%的数据可以直接用\(lucas\)定理卡过去,但你看后面的数据你就会发现事情绝对没有那么简单,应该有亿点技巧在里面,这时候我们就要开始用我们的\(lucas\)定理推柿子了

前置芝士\(lucas\)定理

\(C_{n}^{m}\%p=C_{n/p}^{m/p}*C_{n\%p}^{m\%p}\%p\)
证明建议自己去百度,读者自证不难

正文

有了这个之后我们就可以开始推柿子了
简化题面我们可以得到以下柿子\(\begin{aligned}\sum_{i=0}^kC_{n}^i\%p\end{aligned}\)

这里我们设\(f(n,k)=\sum_{i=0}^kC_{n}^i\)\(p=2333\)

\(lucas\)定理将后面拆开之后可以得到\(\begin{aligned}f(n,k)=\sum_{i=0}^kC_{n}^i=\sum_{i=0}^kC_{n/p}^{i/p}*C_{n\%p}^{i\%p}\end{aligned}\)

随后考虑将两个\(C\)拆开,此时考虑\(i\%p\)的贡献,可以发现p是一个质数,考虑i在小于p的区间内所得到的\(i\%p\)总共有\(0\)~\(p-1\)的贡献,对于i大于p的情况也是同理,那么我们可以得到
\(\begin{aligned}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/p-1}\sum_{i=0}^{p-1}C_{n\%p}^i+C_{n/p}^{k/p}\sum_{i=0}^{k\%p}C_{n\%p}^i\end{aligned}\)

对于最后一块我们先不做处理,然后我们发现可以提公因式,因此我们将\(\begin{aligned}\sum_{i=0}^{P-1}\times C_{n\%P}^{i}\end{aligned}\)

提出来可以得到\(\begin{aligned}(C_{n/p}^0+C_{n/p}^1+...C_{n/p}^{k/p-1})*\sum_{i=0}^{p-1}C_{n\%p}^i\end{aligned}\)

对于前面你还可以提出来一个\(\sum\)变成\(\begin{aligned}\sum_{i=0}^{k/p-1}C_{n\%p}^i\end{aligned}\)

然后我们套用\(\begin{aligned}f(n,k)=\sum_{i=0}^kC_{n}^i\end{aligned}\),可以变成\(\begin{aligned}f(n\%p,p-1)*f(\lfloor \frac np\rfloor , \lfloor \frac kp \rfloor-1)\end{aligned}\)

而对于我们剩下的\(\begin{aligned}C_{n/p}^{k/p}\sum_{i=0}^{k\%p}C_{n\%p}^i\end{aligned}\)

我们也可以拆开变成\(\begin{aligned}C_{n/p}^{k/p}*f(n\%p,m\%p)\end{aligned}\)

那么最后答案可以变为\(\begin{aligned}f(n\%p,p-1)*f(\lfloor \frac np\rfloor , \lfloor \frac kp \rfloor-1)+C_{n/p}^{k/p}*f(n\%p,m\%p)\end{aligned}\)

对于f和c的预处理我们只需要先处理p以内的即可

#include<bits/stdc++.h>

#define LL long long

using namespace std;

template <typename T> void read(T & t) {              
    t = 0;int f = 1;char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-')f =- 1;ch = getchar();}
    do{t = t * 10 + ch - '0';ch = getchar();}while(ch >= '0' && ch <= '9');t *= f;
}

const int kato = 3e3 + 1;

#define mod 2333

int t;

LL inv[kato] , sum[kato] , f[kato][kato];

inline LL quick_pow(LL a , LL b){
    LL res = 1;
    for(; b ; b >>= 1 , a = a * a % mod){
        if(b & 1){
            res = res * a % mod;
        }
    }
    return res % mod;
}

inline LL c(LL n , LL m){
    if(n < m){
        return 0;   
    }
    if(n < mod && m < mod){
        return (sum[n] * quick_pow(sum[m] * sum[n - m] % mod , mod - 2) ) % mod;
    }
    return c(n / mod , m / mod) * c(n % mod , m % mod) % mod;
}

inline LL lucas(LL n , LL m){
    if(n < mod && m < mod){
        return f[n][m];
    }
    else{
        return (c(n / mod , m / mod) * lucas(n % mod , m % mod) + lucas(n % mod , mod - 1) * lucas(n / mod , m / mod - 1)) % mod;
    }
}

inline void init(){
    sum[0] = 1;
    for(int i = 1;i <= kato;i ++){
        sum[i] = (sum[i - 1] * (i % mod) )% mod;
    }
    for(int i = 0;i <= mod;i ++){
        f[i][0] = c(i , 0);
        for(int j = 1;j <= mod;j ++){
            f[i][j] = (f[i][j - 1] + c(i , j)) % mod;
        }
    }
}



inline int Ame_(){
    // freopen("b.in" , "r" , stdin);
    // freopen("b.out" , "w" , stdout);
    read(t);
    init();
    for(LL n , k; t --> 0 ;){
        read(n);read(k);
        LL ans = 0;
        ans = lucas(n , k);
        printf("%lld\n" , ans);
    }
    // fclose(stdin);
    // fclose(stdout);
    return 0;
}

int Ame__ = Ame_();

int main(){;}
posted @ 2020-07-21 21:03  Ame_sora  阅读(236)  评论(0编辑  收藏  举报