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
  • 相关阅读:
    085 Maximal Rectangle 最大矩形
    084 Largest Rectangle in Histogram 柱状图中最大的矩形
    083 Remove Duplicates from Sorted List 有序链表中删除重复的结点
    082 Remove Duplicates from Sorted List II 有序的链表删除重复的结点 II
    081 Search in Rotated Sorted Array II 搜索旋转排序数组 ||
    080 Remove Duplicates from Sorted Array II 从排序阵列中删除重复 II
    079 Word Search 单词搜索
    078 Subsets 子集
    bzoj2326: [HNOI2011]数学作业
    bzoj2152: 聪聪可可
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9686011.html
Copyright © 2011-2022 走看看