zoukankan      html  css  js  c++  java
  • bzoj P4870: [Shoi2017]组合数问题——solution

    题意:求解——

    $$(C^{r}_{nk}+C^{r+k}_{nk}+C^{r+2k}_{nk}+...+C^{r+(n-1)k}_{nk}+...)mod(P)$$

    其中$C^{m}_{n}$表示从n中选m个的方案数

    保证$1 ≤ n ≤ 10^9, 0 ≤ r < k ≤ 50, 2 ≤ p ≤ 2^{30} − 1$

    http://www.lydsy.com/JudgeOnline/problem.php?id=4870

     

    一看r,k很小就很自然地想到矩阵快速幂;

    然后枚举nk

    一开始打算横着递推,处理出每个C,同时处理C的部分和,然而横着递推有问题;

    最后发现竖着递推,直接处理C的部分和非常方便。

    S(x,y)表示C(ik+x,y)的和,可以从S((x-1+k)%k,y-1)+S(x,y-1)得出;

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define LL long long
    using namespace std;
    LL P,N,K,R;
    struct Matrix{
        LL _[55][55];
    };
    Matrix operator * (Matrix a,Matrix b){
        Matrix c;
        int i,j,k;
        memset(c._,0,sizeof(c._));
        for(i=0;i<55;i++)
            for(k=0;k<55;k++)
                if(a._[i][k])
                    for(j=0;j<55;j++)
                        if(b._[k][j])
                            (c._[i][j]+=(a._[i][k]*b._[k][j])%P)%=P;
        return c;
    }
    Matrix x,ret;
    void Sqr(LL );
    int main()
    {
        int i;
        scanf("%lld%lld%lld%lld",&N,&P,&K,&R);
        for(i=0;i<K;i++)
            x._[(i-1+K)%K][i]++,x._[i][i]++;
        Sqr(N*K);
        printf("%lld
    ",ret._[0][R]);
        return 0;
    }
    void Sqr(LL n){
        int i;
        for(i=0;i<55;i++)ret._[i][i]=1;
        while(n){
            if(n&1)
                ret=ret*x;
            n>>=1,x=x*x;
        }
    }

    存在的问题:
    见到组合数就认为不可能在合理的时间内完成行间递推

  • 相关阅读:
    简单函数调用分析
    从函数层面看栈溢出
    C语言漏洞基础(一)
    C语言函数篇(一)
    开发一种填表机器
    阿米洛varmilo键盘
    Flops
    助力高校计算机教育 —— 码云为老师推出免费高校版
    Numerical Methods LetThereBeMath
    Git Cookbook
  • 原文地址:https://www.cnblogs.com/nietzsche-oier/p/8526500.html
Copyright © 2011-2022 走看看