码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ4591——[Shoi2015]超能粒子炮·改

时间:2016-07-13 16:59:25      阅读:196      评论:0      收藏:0      [点我收藏+]

标签:

1、题意:求 C(n,0)+C(n,1)+...+C(n,k)mod2333
2、分析:公式恐惧症的同学不要跑啊QAQ
根据lucas定理——
answer=C(n,0)+C(n,1)+...+C(n,k)mod2333
=C(n/2333,0)?C(nmod2333,0)+C(n/2333,0)?C(nmod2333,1)+...+C(n/2333,k/2333)?C(nmod2333,kmod2333)
这一步大家都能懂吧,这是浅而易见的lucas定理转化过程,将每一项拆分成两项
那么下一步,我们将同类项合并
我们观察可以发现1..2332 / 2333都是0
那么我们将其中2332项提取出来变成
C(n/2333,0)?(C(nmod2333,0)+...+C(mod2333,2332))
同理,2333..4665 / 2333都是1,我们同样提出这个公因式
因此可以得到
C(n/2333,1)?(C(nmod2333,0)+...+C(mod2333,2332))
接下去,我们可以以的到达k/2333-1这里,都是类似的
那么我们提取(C(nmod2333,0)+...+C(mod2333,2332)),得到
(C(n/2333,0)+C(n/2333,1)+...+C(n/2333,k/2333?1))?(C(nmod2333,0)+...+C(mod2333,2332))
我们完成了一部分,那么剩下的还有k/2333的这一部分,我们依旧提取公因式
C(n/2333,k/2333)?(C(nmod2333,0)+...+C(nmod2333,kmod2333))
那么我们令sum(i,j)C(i,0)+C(i,1)+...+C(i,j)
我们可以得到最终答案的式子

ans(n,k)mod2333=(C(n/2333,j)(0j<k/2333))?sum(nmod2333)+C(n/2333,k/2333)?sum(nmod2333,kmod2333)

我们观察这个式子(C(n/2333,j)(0j<k/2333)),他简直就是这个问题的简化版
那么这个式子其实是等于ans(n/2333,k/2333?1) 的,十分浅显易懂,那么我们就可以将此题不断的缩小再缩小,注意那个C数组和sum数组都预处理出来,只预处理小于2333的,太大的C用lucas定理解决,完美解决,撒花!

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 2500
#define MOD 2333 
#define LL long long

inline int read(){
    char ch = getchar(); int x = 0, f = 1;
    while(ch < ‘0‘ || ch > ‘9‘){
        if(ch == ‘-‘) f = -1;
        ch = getchar();
    }
    while(‘0‘ <= ch && ch <= ‘9‘){
        x = x * 10 + ch - ‘0‘;
        ch = getchar();
    }
    return x * f;
}

inline LL llread(){
    char ch = getchar(); LL x = 0, f = 1;
    while(ch < ‘0‘ || ch > ‘9‘){
        if(ch == ‘-‘) f = -1;
        ch = getchar();
    }
    while(‘0‘ <= ch && ch <= ‘9‘){
        x = x * 10 + ch - ‘0‘;
        ch = getchar();
    }
    return x * f;
}

int c[M][M], sum[M][M];  

inline void init(){
    c[0][0] = sum[0][0] = 1;
    for(int i = 1; i < MOD; i ++) sum[0][i] = 1;
    for(int i = 1; i < MOD; i ++){
        sum[i][0] = c[i][0] = 1;
        for(int j = 1; j <= i; j ++) c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % MOD;
        for(int j = 1; j < MOD; j ++) sum[i][j] = (sum[i][j - 1] + c[i][j]) % MOD;
    }
}


inline int Lucas(LL x, LL y){
    if(x < y || y < 0) return 0;   
    if(x < MOD && y < MOD) return c[x][y];  
    return Lucas(x / MOD, y / MOD) * c[x % MOD][y % MOD] % MOD;  
}  

inline int cal(LL n, LL k){
    if(k < 0) return 0;  
    return (cal(n / MOD,k / MOD - 1) * sum[n % MOD][MOD - 1] % MOD + Lucas(n / MOD, k / MOD) * sum[n % MOD][k % MOD] % MOD) % MOD;  
}  

int main(){
    init();
    int T = read();
    while(T --){
        LL n = llread(), k = llread();
        printf("%d\n", cal(n, k));
    }
    return 0;
}

BZOJ4591——[Shoi2015]超能粒子炮·改

标签:

原文地址:http://blog.csdn.net/qzh_1430586275/article/details/51893154

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!