篮球训练——解题报告

题目链接:http://172.18.70.217/problem/8
本体的题意很明确就是给了我们爬楼梯一步能走几级台阶的一些情况,让我们求出爬到第n级台阶有多少种可能性。
首先,很明显的是这是一道动态规划题,状态转移方程也非常好写,状态转移方程方程如下:
dp[i]=∑dp[i-k] (k为爬楼梯的其中一种方案,i为第几层台阶)
然而你很快会绝望的发现n的大小是1000位。这意味着传统的动态规划已经不能解决这个问题了,但是第i层楼梯的方案确实有i-k层的答案贡献。所以我们需要一种优化方案,将时间复杂度下降。
为了解决O(n)的时间复杂度的问题,因为n有1000位的缘故,所以最大也要O(logn)才能保证不超时,而同时又是动态规划的优化,故我们很容易想到利用矩阵快速幂来优化。
那么怎么构建这样一个矩阵呢?按照正常套路,矩阵(i,j)表示状态i–>状态j。而对于答案矩阵来说,因为最大的步数已知,所以下一维的状态不可能由更多状态转移而来了,所以矩阵最大就是(1*20),而第一位f[0]=1,所以矩阵设计为:
这里写图片描述
而我们就可以根据答案矩阵设计出转移矩阵了,因为要f[n]要转移到f[n+1],所以矩阵第一行所有先前输入的p[i]的值为1其余为0,而为了下一位由f[n-1]到f[n],所以只有f[n]对应位为1,依次下来之后就是(i,i-1)为1,其余各位为0。以样例来举例,转移矩阵为:
这里写图片描述
接下来就可以利用矩阵快速幂来加速了,由于时间卡得较死,我们需要记录一些已经计算过的情况,用f[i][j]表示第i位为j的矩阵的值。意思就是这个值的快速幂计算值,下面附上AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define mod 64123

using namespace std;
typedef long long ll;
struct matrix
{
    ll n;
    ll a[30][30];
}before[1010][12];
ll T,K,M,p[30];
ll Max=0;
matrix matrix_mul(matrix A, matrix B)
{
    matrix ret;
    ret.n=A.n;
    for(ll i=1;i<=ret.n;i++)
        for(ll j=1;j<=ret.n;j++)
            ret.a[i][j]=0;
    for(ll i=1;i<=ret.n;i++)
        for(ll j=1;j<=ret.n;j++)
            for (ll k=1;k<=A.n;k++)
                ret.a[i][j]=(ret.a[i][j]+A.a[i][k]*B.a[k][j]%mod)%mod;
    return ret;
}
matrix mul(matrix A,matrix B)
{
    matrix ret;
    ret.n=A.n;
    for(ll i=1;i<=ret.n;i++)
        for(ll j=1;j<=ret.n;j++)
            ret.a[i][j]=0;
    for(ll j=1;j<=ret.n;j++)
        for (ll k=1;k<=A.n;k++)
            ret.a[1][j]=(ret.a[1][j]+A.a[1][k]*B.a[k][j]%mod)%mod;
    return ret;
}
matrix unit(ll n)
{
    matrix ret;
    ret.n=n;
    for(ll i=1;i<=n;i++)
    {
        for(ll j=1;j<=n;j++)
        {
            if(i==j)
                ret.a[i][j]=1;
            else
                ret.a[i][j]=0;
        }
    }
    return ret;
}
bool vis[1010][20];
matrix dfs(const int &bit, const int &i)
{
    if(!i)
        return before[0][0];
    if(vis[bit][i])
        return before[bit][i];
    vis[bit][i]=true;
    if(bit==0)
    {
        if(i&1)
            return before[bit][i]=matrix_mul(dfs(bit,i-1),dfs(bit, 1));
        else
            return before[bit][i]=matrix_mul(dfs(bit,i>>1),dfs(bit,i>>1));
    }
    if(i==1)
        return before[bit][i]=dfs(bit-1,K);
    if(i&1)
        return before[bit][i]=matrix_mul(dfs(bit,i-1),dfs(bit,1));
    else
        return before[bit][i]=matrix_mul(dfs(bit,i>>1),dfs(bit,i>>1));
}
int main()
{
    scanf("%lld%lld%lld",&T,&K,&M);
    for(ll i=1;i<=M;i++)
    {
        scanf("%lld",&p[i]);
        Max=max(Max,p[i]);
    }
    matrix move;
    move.n=Max;
    for(ll i=2;i<=Max;i++)
        move.a[i][i-1]=1;
    for(ll i=1;i<=M;i++)
        move.a[1][p[i]]=1;
    before[0][0]=unit(Max);
    before[0][1]=move;
    vis[0][0]=vis[0][1]=true;
    while(T--)
    {
        char s[1010];
        scanf("%s",s);
        ll len=strlen(s);
        matrix ans;
        ans.n=Max;
        for(ll i=1;i<=Max;i++)
            for(ll j=1;j<=Max;j++)
                ans.a[i][j]=0;
        ans.a[1][1]=1;
        for(ll i=len-1;i>=0;i--)
        {
            ll num=s[i]-'0';
            ans=mul(ans,dfs(len-1-i,num));
        }
        printf("%lld\n",ans.a[1][1]);
    }

    return 0;
}

根据计算可得,时间复杂度大致为O(strlen(n) * log(n) * 400)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值