zoukankan      html  css  js  c++  java
  • BZOJ-2-4870: [Shoi2017]组合数问题 矩阵优化 DP

    就 是 要 我 们 从  n k  件 物 品 里 面 选 出 若 干 件,使 得 其 数 量 模 k 等 于 r 的 方 案 数 。
    dp方程 f [ i , j ] 表示前 i 件物品拿了若干件使得其数量模 k 等 于 j 的 方 案 数。

    非常明显的 i 与 i - 1递推的DP,  可以转化推矩阵,进行矩阵乘法。

    那么显然有f [ i , j ] =  f [ i − 1 ,j ]  + f[ i − 1,j − 1 ]  f [  i , j ]= f  [ i  − 1,j ]+ f [ i − 1, j − 1 ]
    矩阵乘法优化即可,注意 k等于 1时 矩阵初始化  需要一直 ++而不是赋值为 1。

    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 55
    #define ll long long
    ll n,mod,k,r;
    struct node
    {
        ll sx,sy;
        ll num[maxn][maxn];
        void up1()
        {
            for(int i=0; i<sx; i++)
                for(int j=0; j<sy; j++)
                    num[i][j]=0;
        }
    } A,ans;
    node operator*(node a,node b)
    {
        node c;
        c.sx=a.sx,c.sy=b.sy;
        c.up1();
        for(int i=0; i<a.sx; i++)
            for(int j=0; j<b.sy; j++)
                for(int q=0; q<a.sy; q++)
                    c.num[i][j]=(c.num[i][j]%mod+a.num[i][q]%mod*b.num[q][j]%mod)%mod;
        return c;
    }
    void qpow(ll b)
    {
        while(b)
        {
            if(b%2)
                ans=ans*A;
            A=A*A;
            b>>=1;
        }
    }
    int main()
    {
        scanf("%lld%lld%lld%lld",&n,&mod,&k,&r);
        ans.sx=1;
        ans.sy=A.sx=A.sy=k;
        A.up1();
        ans.up1();
        ans.num[0][0]=1;
        for(int i=0; i<k; i++)
        {
            A.num[i][i]=1;
            A.num[i][(i+1)%k]++;
        }
        qpow(n*k);
        printf("%lld
    ",ans.num[0][r]);
        return 0;
    }
    

      

  • 相关阅读:
    Bzoj4627 [BeiJing2016]回转寿司
    Bzoj1901 Zju2112 Dynamic Rankings
    COGS728. [网络流24题] 最小路径覆盖问题
    Bzoj4568 [Scoi2016]幸运数字
    Bzoj2728 [HNOI2012]与非
    HDU4609 3-idiots
    Bzoj2194 快速傅立叶之二
    Bzoj2179 FFT快速傅立叶
    模拟52 题解
    模拟51 题解
  • 原文地址:https://www.cnblogs.com/SDUTNING/p/10241334.html
Copyright © 2011-2022 走看看