【LOJ】#2038. 「SHOI2015」超能粒子炮・改

题解

用lucas随便分析一波就出来了

(inom{n}{k} = inom{n % p}{k % p}inom{n / p}{k / p})
那么对于一个余数r,如果r <= k % p
那么它还要乘上
(sum_{i = 0}^{lfloor frac{k}{p} floor} inom{lfloor frac{n}{p} floor % p}{i})
这显然是个相同的问题,可以递归
如果r > k % p那么会比前一个问题少乘一个(inom{lfloor frac{n}{p} floor % p}{lfloor frac{k}{p} floor})
这样我们处理下2333以内每行组合数的前缀和,再递归处理,可以用(log^2 n)的复杂度内解决,但是别忘了底数是p,超级快的。。。

代码

#include <bits/stdc++.h>
#define enter putchar('
')
#define space putchar(' ')
#define pii pair<int,int>
#define fi first
#define se second
#define MAXN 200005
#define pb push_back
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;T f = 1;char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
        res = res * 10 + c - '0';
        c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) out(x / 10);
    putchar('0' + x % 10);
}
const int MOD = 2333;
int C[2335][2335],S[2335][2335];
int inc(int a,int b) {
    return a + b >= MOD ? a + b - MOD : a + b;
}
int mul(int a,int b) {
    return a * b % MOD;
}
int Cnm(int64 n,int64 m) {
    int res = 1;
    while(1) {
        if(n < m || !res) {return 0;}
        if(n == 0) break;
        res = mul(res,C[n % MOD][m % MOD]);
        n /= MOD;m /= MOD;
    }
    return res;
}
int Calc(int64 n,int64 k) {
    if(!n) return 1;
    int64 t = k / MOD;int r = k % MOD;
    int h2 = Cnm(n / MOD,t);
    int h1 = Calc(n / MOD,t);
    h2 = inc(h1,MOD - h2);
    return inc(mul(S[n % MOD][r],h1),mul(inc(S[n % MOD][MOD - 1],MOD - S[n % MOD][r]),h2));
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    C[0][0] = 1;
    for(int i = 1 ; i < MOD ; ++i) {
        C[i][0] = 1;
        for(int j = 1 ; j <= i ; ++j) {
            C[i][j] = inc(C[i - 1][j - 1],C[i - 1][j]);
        }
    }
    for(int i = 0 ; i < MOD ; ++i) {
        S[i][0] = 1;
        for(int j = 1 ; j < MOD ; ++j) {
            S[i][j] = inc(S[i][j - 1],C[i][j]);
        }
    }
    int T;
    int64 N,K;
    read(T);
    while(T--) {
        read(N);read(K);
        out(Calc(N,K));enter;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/ivorysi/p/9491292.html