守望者的烦恼(By Python)

题目描述
头脑并不发达的warden最近在思考一个问题,她的闪烁技能是可以升级的,k级的闪烁技能最多可以向前移动k个监狱,一共有n个监狱要视察,她从入口进去,一路上有n个监狱,而且不会往回走,当然她并不用每个监狱都视察,但是她最后一定要到第n个监狱里去,因为监狱的出口在那里,但是她并不一定要到第1个监狱。
守望者warden现在想知道,她在拥有k级闪烁技能时视察n个监狱一共有多少种方案?

输入数据
第一行是闪烁技能的等级 k (1≤k≤10)
第二行是监狱的个数 n (1≤n≤231−1)

输出数据
由于方案个数会很多,所以输出它 mod 7777777后的结果就行了

样例输入
2
4
样例输出
5

这道题的话其实如果只是当做动态规划的其实是挺简单的,因为这个的子问题其实很好分,这样一来思路其实就很明确了,这里题目说的是到最后的n监狱的方案,其实就是n-k到n-1这几个监狱的方案数之和(这个应该就不用多说了吧)
这样一来,我们就有了第一个版本的代码提交:

k=int(input())
n=int(input())
a=[0]
for i in range(1,n+1):
    add=0
    flag=0
    for j in range(1,k+1):
        if i-j<=0 and flag==0:
            add+=1
            flag=1
        else:
            add+=a[i-j]
    a.append(add)
print(a[n]%7777777)

这个代码本身没什么问题,考虑了前面k个监狱的直接跳的次数,整个列表从左到右很好算,但是问题其实是很明显的:
第一,只有最后一个模除的话其实前面的计算压力还是很大
第二,按照最大的数据规模来看,难道要开一个九位数的数组吗,这明显不合适。
所以很明显,这个题这样在OJ上是过不了的。。
接下来就需要进行一下思路的转变了,子问题公式不变,所以新的方案不算难想,就是用一个k长的列表,先存前k个监狱的方案数,之后每一次都是更新其中的一个元素同时放弃监狱号最小的,最后得到结果。这个方案对于空间的占用明显会小不少,但是在这里我们会发现一下,那就是如果列表每一次改变的值的下标不一定的话其实是比较麻烦的,而且我们意识到,如果用矩阵乘法实现数值更新的话,不仅可以调整位置,更新数据,而且可以利用矩阵结合律+快速幂来简化计算,这样我们就得到了最后的代码:

k=int(input())
n=int(input())
mod=7777777
a=[]
sum=0
for i in range(k):
    add=0
    add=sum+1
    a.append(add)
    sum+=add
# print(a)
if k>=n:
    print(a[n-1])
else:
    b=[[0 for i in range(k)]for i in range(k)]
    for i in range(k):
        b[i][k-1]=1
        if i+1<k:
            b[i+1][i]=1

    # print(a)

    def mulMatrix(x,y,k):
        ans = [[0 for i in range(k)]for j in range(k)]
        for i in range(k):
            for j in range(k):
                for l in range(k):
                    ans[i][j] = (ans[i][j] + (x[i][l] * y[l][j])%mod)%mod
        return ans

    def quickMatrix(m,n,k):
        E = [[0 for i in range(k)]for j in range(k)] 
        for i in range(k):
            E[i][i] = 1
        while(n):
            if n % 2 == 1:
                E = mulMatrix(E,m,k)
            m = mulMatrix(m,m,k)
            n=int(n/2)
        return E

    def mymul(x,y,k):
        mid=[0 for i in range(k)]
        for i in range(k):
            for j in range(k):
                mid[i]=(mid[i]+(x[j]*y[j][i])%mod)%mod
        return mid
     
    # print(quickMatrix(b,n,k))
    # print(quickMatrix(b,n-k,k))
    print(mymul(a,quickMatrix(b,n-k,k),k)[k-1])

思路对了之后,这里需要注意的点就少了很多,主要是矩阵的乘法这里,因为矩阵乘法中的一维乘二维和二维乘二维还是有一些不一样的,这里需要写两个函数。(主要是兼容的那个要进行数值类型变化而我又刚好不会)。最后成功AC。
这次这道OJ题目属实是顶级折磨,我做这道题直接碰到了基本全部类型的错误(除了TLE),实在是太过经典了所以我一定要把这个摆出来(捂脸)
在这里插入图片描述

对于守望者的逃离这道题目,可以使用动态规划或贪心算法来解决。首先我们需要理解题目的要求,甲在光明大道的起始点,每秒有三种选择:1.行使17m,2.在蓝量足够的情况下行使60m,蓝量减去10,3.行使0m,恢复4蓝量。我们需要判断甲能否在初始蓝量为m的情况下在t秒内到达终点。 为了解决这个问题,我们可以使用一个循环来模拟每一分钟的情况。假设甲在当前的时间点有一定的蓝量,我们可以计算出他在下一分钟时的蓝量,并根据这个蓝量来判断他的行动选择。如果蓝量足够,我们选择行使60m并减去10的蓝量;如果蓝量不足,我们选择行使17m;如果蓝量为0,我们选择恢复4蓝量。 在每一分钟的计算中,我们需要对甲的位置进行更新,并记录下他到达终点的最短时间。当循环结束后,我们可以得到甲是否能在规定时间内到达终点,如果能,输出"Yes"并换行输出所需时间;如果不能,输出"No"并换行输出甲最长能达到的距离。 这样,我们就可以使用C语言编写代码来解决守望者的逃离这道题目了。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [[NOIP2007 普及组] 守望者的逃离](https://blog.csdn.net/TGxyt_blog/article/details/122783995)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值