Luogu4345 SHOI2015 超能粒子炮·改 Lucas、数位DP

传送门


模数小,还是个质数,Lucas没得跑

考虑Lucas的实质。设(a = sumlimits_{i=0}^5 a_i 2333^i)(b = sumlimits_{i=0}^5 b_i2333^i),那么(C_a^b mod2333 = prodlimits_{i=0}^5 C_{a_i}^{b_i} mod 2333)

可以认为Lucas就是将(a,b)两个数化成(2333)进制数之后每一位组合运算的乘积。似乎与数位相关,使用类似于数位DP的思考方式,从高到低填数。

因为现在需要求的是(sumlimits_{i=0}^k C_n^i),假设(k)(2333)进制下表示为(overline {k_5k_4k_3k_2k_1k_0})(n)(2333)进制下表示为(overline{n_5n_4n_3n_2n_1n_0}),那么对于第(5)(< k_5)的数,后面的四位一定会取到(0)(2332)的所有值。我们处理出(prod limits _{i=0}^4 sumlimits_{j=0}^{2332} C_{n_i}^j),根据二项式定理这其实就是(2^{n_0+n_1+n_2+n_3+n_4}),那么(2333)进制下第(5)(<k_5)的所有数的贡献就是(2^{n_0+n_1+n_2+n_3+n_4}sumlimits_{i=0}^{k_5-1}C_{n_5}^i)

最后考虑第(5)位等于(k_5)的情况,在这种情况下接着考虑第(4)位,方式跟上面一致,不断做下去直到所有位都被考虑完。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<vector>
#include<cmath>
#define ll long long
//This code is written by Itst
using namespace std;

inline ll read(){
    ll a = 0;
    char c = getchar();
    bool f = 0;
    while(!isdigit(c) && c != EOF){
        if(c == '-')
            f = 1;
        c = getchar();
    }
    if(c == EOF)
        exit(0);
    while(isdigit(c)){
        a = a * 10 + c - 48;
        c = getchar();
    }
    return f ? -a : a;
}

const int MOD = 2333;
int C[MOD][MOD] , inv[MOD] , sum[6] , mod[6];
ll powM[6];

inline int poww(int a , int b){
    int times = 1;
    while(b){
        if(b & 1)
            times = times * a % MOD;
        a = a * a % MOD;
        b >>= 1;
    }
    return times;
}

int calc(ll cur , int now){
    if(now < 0)
        return 1;
    if(cur / powM[now])
        return (C[mod[now]][cur / powM[now] - 1] * sum[now] + (C[mod[now]][cur / powM[now]] - C[mod[now]][cur / powM[now] - 1] + MOD) * calc(cur % powM[now] , now - 1)) % MOD;
    return calc(cur , now - 1);
}

void init(){
    powM[0] = sum[0] = 1;
    for(int i = 1 ; i <= 5 ; ++i)
        powM[i] = powM[i - 1] * MOD;
    C[0][0] = 1;
    for(int i = 1 ; i < MOD ; ++i){
        C[i][0] = 1;
        for(int j = 1 ; j < MOD ; ++j)
            C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD;
    }
    for(int i = 0 ; i < MOD ; ++i)
        for(int j = 1 ; j < MOD ; ++j)
            C[i][j] = (C[i][j] + C[i][j - 1]) % MOD;
}

signed main(){
#ifndef ONLINE_JUDGE
    freopen("in","r",stdin);
    freopen("out","w",stdout);
#endif
    init();
    for(int T = read() ; T ; --T){
        ll N = read() , K = read();
        for(int i = 1 ; i <= 5 ; ++i){
            mod[i - 1] = N / powM[i - 1] % 2333;
            sum[i] = poww(2 , mod[i - 1]) * sum[i - 1] % MOD;
        }
        mod[5] = N / powM[5];
        cout << calc(K , 5) << '
';
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Itst/p/10345189.html