zoukankan      html  css  js  c++  java
  • Luogu 4345 [SHOI2015]超能粒子炮·改

    BZOJ4591

    并不会写的组合数学。

    我们设$f(n, k) = sum_{i= 0}^{k}inom{n}{i}$,那么每一个询问要求的就是$f(n, k)$。

    发现$f(i, j)$其实可以递推:

        $f(i, 0) = 1$

        $f(i, j) = f(i, j - 1) + inom{i}{j}$

    看上去没什么用处,但是我们还有$Lucas$定理。

        $f(n, k) = sum_{i = 0}^{k}inom{n}{i} (Mod P) =sum_{i = 0}^{k}inom{left lfloor frac{n}{P} ight floor}{left lfloor frac{i}{P} ight floor} * inom{n\%p}{i\%p}$

    看到了$left lfloor frac{i}{P} ight floor$这个东西,其实我们知道这个东西一共只有$sqrt{P}$种取值,所以我们把一样的东西提出来,一共有$left lfloor frac{k}{p} ight floor - 1$个完整的循环节,还有一个不完整的循环节是$inom{left lfloor frac{n}{P} ight floor}{left lfloor frac{k}{P} ight floor}sum_{i = 0}^{k \% P}inom{n\% P}{i}$。

    加起来:

        $sum_{i = 0}^{left lfloor frac{k}{p} ight floor - 1}inom{left lfloor frac{n}{P} ight floor}{i}sum_{j = 0}^{P - 1}inom{n \% P}{j} + inom{left lfloor frac{n}{P} ight floor}{left lfloor frac{k}{P} ight floor}sum_{i = 0}^{k \% P}inom{n\% P}{i}$

    发现其实是若干个子问题的叠加:

        $f(left lfloor frac{n}{P} ight floor , left lfloor frac{k}{P} ight floor - 1)* f(n \% P , P - 1) + f(n \% P , k \% P) * inom{left lfloor frac{n}{P} ight floor}{left lfloor frac{k}{P} ight floor}$

    这样子对于所有的$f$,我们直接递归求解,小于模数的$f$可以直接递推预处理,可以发现递归深度一定不会超过$log$层,还有一个组合数,用$Lucas$定理算一波就好了。

    时间复杂度$O(P^2 + Tlogn)$,$log$的底数为$2333$。

    Code:

    #include <cstdio>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    
    const int N = 2505;
    const int P = 2333;
    
    int testCase, c[N][N], f[N][N];
    
    inline int lucas(ll n, ll m) {
        if(m == 0LL) return 1;
        if(n < P && m < P) return c[n][m];
        return lucas(n / P, m / P) * c[n % P][m % P] % P;
    }
    
    inline int solve(ll n, ll k) {
        if(k == -1LL) return 0;
        if(n < P && k < P) return f[n][k];
        return (solve(n / P, k / P - 1) * solve(n % P, P - 1) % P + lucas(n / P, k / P) * solve(n % P, k % P) % P) % P;
    }
    
    int main() {
        c[0][0] = 1;
        for(int i = 1; i <= P; i++) {
            c[i][0] = 1;
            for(int j = 1; j <= i; j++)
                c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % P;
        }
        
        for(int i = 0; i <= P; i++) {
            f[i][0] = 1;
            for(int j = 1; j <= P; j++)
                f[i][j] = (f[i][j - 1] + c[i][j]) % P;
        }
        
        for(scanf("%d", &testCase); testCase--; ) {
            ll n, K; scanf("%lld%lld", &n, &K);
            printf("%d
    ", solve(n, K));
        }
        
        return 0;
    }
    View Code
  • 相关阅读:
    JS 利用数组拼接html字符串
    IE浏览器下读取客户端上传的文件大小
    PrintWriter out = response.getWriter() 输出中文乱码问题
    非常有用的Java程序片段
    sql之left join、right join、inner join的区别
    JAVA 数组常用技巧
    java 图片文件格式转换(多页tif转jpg 、jpg转tif)
    SQL Server 字段状态判断语句
    sql server 2008中id如何设为自增
    java基于xml配置的通用excel单表数据导入组件(五、Action处理类)
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9686011.html
Copyright © 2011-2022 走看看