• P4345 [SHOI2015]超能粒子炮·改


    传送门

    看到数据和模数大小就知道要上 lucas 了

    然后开始愉快地推公式:

    答案为 $sum _{i=0}^kC_{n}^{i} (mod 2333)$

    设 $f [ i ] [ j ] = sum _{k=0}^jC_{i}^{k} (mod 2333) , P=2333$

    那么根据 lucas 定理得 $f[n][k]=sum _{i=0}^k {C_{n\%P}^{i\%P}C_{n/P}^{i/p}}$

    看到 $i/P$ 容易想到整除分块,那就把 $i/P$ 相同的块提出来看看

    $=C_{n/P}^{0} sum _{i=0}^{p-1}{C_{n\%P}^{i}}+C_{n/P}^{1} sum _{i=0}^{p-1}{C_{n\%P}^{i}}+...+ C_{n/P}^{k/P}sum _{i=0}^{k\%P}{C_{n\%P}^{i}}$

    把$sum _{i=0}^{p-1}{C_{n\%P}^{i}}$ 提出来,得到

    $=sum _{i=0}^{p-1}{C_{n\%P}^{i}}(C_{n/P}^{0}+C_{n/P}^{1}+...+C_{n/P}^{k/P-1})+ C_{n/P}^{k/P}sum _{i=0}^{k\%P}{C_{n\%P}^{i}}$

    那就可以写成 $=f[n\%P][P-1]cdot f[n/P][k/P-1]+ C_{n/P}^{k/P}f[n\%P][k\%P]$

    然后就可以递归下去求了

    注意long long

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    inline ll read()
    {
        ll x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int M=3007,mo=2333;
    inline ll fk(ll x) { return x>=mo ? x-mo : x; }
    int T;
    ll N,K,f[M][M],C[M][M];
    inline ll lucas(ll a,ll b)//lucas不解释
    {
        if(a<b) return 0;
        if(!b||a==b) return 1;
        return C[a%mo][b%mo]*lucas(a/mo,b/mo)%mo;
    }
    inline ll F(ll n,ll k)
    {
        if(k<0) return 0; if(!n||!k) return 1;//边界
        if(n<mo&&k<mo) return f[n][k];//边界
        return fk( F(n/mo,k/mo-1)*f[n%mo][mo-1]%mo + lucas(n/mo,k/mo)*f[n%mo][k%mo]%mo );
    }
    void pre()//预处理,注意C和f范围不同
    {
        C[0][0]=f[0][0]=1;
        for(int i=1;i<=mo;i++)
        {
            C[i][0]=C[i][i]=f[i][0]=1;
            for(int j=1;j<i;j++) C[i][j]=fk(C[i-1][j]+C[i-1][j-1]);
        }
        for(int i=0;i<=mo;i++)
            for(int j=1;j<=mo;j++) f[i][j]=fk(f[i][j-1]+C[i][j]);
    }
    int main()
    {
        pre();
        scanf("%d",&T);
        while(T--)
        {
            N=read(); K=read();
            printf("%lld
    ",F(N,K));
        }
        return 0;
    }
  • 相关阅读:
    oracle sql 汉字在库中占的字节数
    面试题:反转单词顺序
    面试题:平衡二叉树
    面试题:二叉树的深度
    面试题:二叉树的下一个节点
    面试题:数字在排序数组中出现的次数
    面试题:把数组排成最小的数
    面试题:二叉树与双向搜索树
    面试题:序列化二叉树
    面试题:字符串的全排列
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/9914369.html
Copyright © 2020-2023  润新知