备战蓝桥杯python组——dp

备战蓝桥杯python组

  • 小红取数
  • 解题思路
    • 转移方程的确定
  • 整体代码

小红取数

链接: 小红取数
备战蓝桥杯python组——dp_第1张图片
初看题目,并不能分析出来规律,只用用相对暴力的方法进行“试错”。
由此,我们考虑使用动态规划dp来简化暴搜的过程

解题思路

确定好了使用dp,我们就要来分析dp的重中之重:动态转移方程

转移方程的确定

取数要求我们这个数%k==0,我们就要考虑将dp数组与给出的数字和加和的余数相联系起来,于是我们设:

dp[i][j]: 前i个数中(包含i)余数为j的最大和

明白了dp定义,我们来讲解状态转移方程

我们先要明确一点,当前dp[i][j]的由来可以有两个大的方向:
1.不加上当前遍历到的数字ii
2.j是由 (x+a[t]) % k ==j 中的状态x转移过来的

首先,我们来考虑当前状态dp[i][j],在不加当前遍历数字的情况下是如何得来的
无外乎两种情况:
1.由前i-1个数中,余数为k的最大数得来,也就是dp[i-1][j]
2.保持现在状态不变,也就是dp[i][j]

二者间取较大的,所以我们第一个状态转移方程为:
  d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , d p [ i − 1 ] [ j ] )   . \ dp[i][j] = max(dp[i][j], dp[i-1][j])\,.  dp[i][j]=max(dp[i][j],dp[i1][j]).
我们再来回顾一下dp状态求得的思路:
1.不加上当前遍历到的数字ii
2.j是由 (x+a[t]) % k ==j 中的状态x转移过来的

这只是其中的部分情况,我们还并没有加上当前遍历的数字,如果加上当前遍历的数字,此时我们求得的并不是当前dp[i][j]的状态,而是余数为 (j+a[i])%k时的状态,此时我们的dp[i-1][j]相当于上文提及到的x,状态转移方程为:
  d p [ i ] [ ( d p [ i − 1 ] [ j ] + a [ i ] ) % k ] = m a x ( d p [ i − 1 ] [ j ] + a [ i ] , d p [ i ] [ ( d p [ i − 1 ] [ j ] + a [ i ] ) \ dp[i][(dp[i-1][j]+a[i]) \% k] = max(dp[i-1][j]+a[i],dp[i][(dp[i-1][j]+a[i])%k]) \,.  dp[i][(dp[i1][j]+a[i])%k]=max(dp[i1][j]+a[i],dp[i][(dp[i1][j]+a[i])

代码

for i in range(1, n+1):
    for j in range(k):
        # 不加位置i的数字
        dp[i][j]=max(dp[i-1][j],dp[i][j])
        # 加位置i的数字
        dp[i][(dp[i-1][j]+a[i])%k]=max(dp[i-1][j]+a[i],dp[i][(dp[i-1][j]+a[i])%k])

整体代码

n, k = map(int, input().split())
a=[0]
a += [int(i) for i in input().split()]
dp = [[0]* k for _ in range(n+1)]
for i in range(1, n+1):
    for j in range(k):
        # 不加位置i的数字
        dp[i][j]=max(dp[i-1][j],dp[i][j])
        # 加位置i的数字
        dp[i][(dp[i-1][j]+a[i])%k]=max(dp[i-1][j]+a[i],dp[i][(dp[i-1][j]+a[i])%k])

if dp[n][0]==0:
    print(-1)
else:
    print(dp[n][0])

你可能感兴趣的:(蓝桥杯冲刺,python,蓝桥杯,python)