无题的题目

啊 我的答案有错误

---------------------------------------------------------------

题目:

给定正整数N和D,生成所有行和、列和等于D的NxN的非负整数矩阵。给出 N <= 5, D <= 8 的每一个<N, D>下这样的矩阵的数目

 

 

当N = 2, D = 1时,有 1 0             0 1 两种情况

                                       0 1             1 0

当N = 2, D = 2时,有 2 0           0 2           1 1 三种情况

                                        0 2           2 0           1 1

等等等等

由此我们可以看出 N = n, D = d 是由N = n, D = 1种选d个组合形成的

所以问题现在变成:1、2、3…n个数 从里面拿m个(可重复拿) 有多少种情况;

比如n = 2, m = 2,  11, 22, 33, 12, 13, 23 一共6种情况

 

然后我们祭出排列组合中的隔板法。。不会的可以去查。。组合是这个:Cn + m - 1, n - 1

 

然后数可能会超过int,所以用的python 

def solution(n, m):
    return a[n + m - 1] // (a[n - 1] * a[m])

a = [1] * (3200 + 5)
a[1] = 1
for i in range(2, 3200):
    a[i] = a[i - 1] * i
n = int(input())
m = int(input())

print(solution(a[n], m))

<think>好的,我现在需要解决这个问题,题目是说给定一个二维数组questions,每个元素包含pointsibrainpoweri。按顺序处理每个问题,可以选择解决或者跳过。如果解决的话,能获得对应的分数,但接下来必须跳过brainpoweri个问题。如果跳过的话,就继续下一个问题。最终要返回能获得的最高分数。那这个问题应该怎么想呢? 首先,这感觉像是一个动态规划的问题。因为每个步骤的选择会影响后面的状态,而且需要找到最优解。动态规划的关键在于找到状态转移方程。 那状态应该怎么定义呢?可能的状态应该是当前处理到的问题索引i,以及在这个位置时所能获得的最大分数。假设我们用dp[i]表示处理到第i个问题时可以得到的最大分数。那么对于每个问题i,我们有选择解决或者跳过两种情况: 1. 如果解决i,那么获得的分数是points[i],然后接下来的brainpower[i]个问题必须跳过。所以下一个能处理的问题就是i + brainpower[i] + 1。此时,dp[i] = points[i] + dp[i + brainpower[i] + 1](如果后面的情况存在的话)。 2. 如果跳过i,那么分数变,直接处理下一个问题i+1。此时,dp[i] = dp[i+1]。 所以,对于每个i,dp[i]应该取这两个情况的最大值。 但是这里需要注意的是,如果我们从后往前推导的话,可能更容易处理。因为后面的结果在计算前面的时候已经确定。例如,最后一个问题i=n-1,如果解决的话,就只能获得points[n-1],然后后面没有问题了。如果跳过的话,得0。所以dp[n-1] = max(points[n-1], 0)。或者可能题目中允许跳过的时候,还可以继续处理下一个,比如当i是最后一个时,跳过的话就没有后续,所以此时的最大值就是max(解决它得分,或者解决得0)。或者可能我的状态定义需要调整? 或者,可能应该将dp[i]定义为从第i个问题开始到末尾所能获得的最大分数。这样的话,对于每个i,我们有两种选择: - 解决i:获得points[i],然后必须跳过接下来的brainpower[i]个问题,所以下一个能处理的是i + brainpower[i] +1。那么总分数是points[i]加上从i + brainpower[i] +1开始的最大分数,也就是points[i] + dp[i + brainpower[i] +1] - 解决i:那么可以处理i+1的问题,此时总分数是dp[i+1] 所以,dp[i] = max(points[i] + dp[next], dp[i+1]) 其中next = i + brainpower[i] +1 这样,初始条件应该是dp[n] =0,因为当i超过数组长度时,没有分数。 然后从后往前计算每个dp[i]。 比如例子中的questions = [[3,2],[4,3],[4,4],[2,5]] n=4,所以dp数组长度是5(0~4),dp[4]=0. i=3的时候: 解决的话,得分2,然后要跳过5个问题,所以next是3+5+1=9,超过数组长度,所以是0。总得分2+0=2。或者解决的话,得分是dp[4]=0。所以dp[3] = max(2,0)=2。 i=2的时候: 解决的话,得分4,next是2+4+1=7>3,所以得4+0=4。解决的话,得分是dp[3]=2。所以dp[2]=max(4,2)=4. i=1的时候: 解决的话,得分4,next是1+3+1=5>3,所以得分4+0=4。解决的话,得分是dp[2]=4。所以dp[1]=max(4,4)=4. i=0的时候: 解决的话,得分3,next是0+2+1=3。dp[3]=2,所以总得分3+2=5。解决的话,得分是dp[1]=4。所以max(5,4)=5。所以最终答案是5。 这样,这个例子中得到的答案是5,正确。所以这个状态转移是正确的。 那么,动态规划的思路应该是正确的。现在问题是如何实现这个算法。 具体来说,需要初始化一个dp数组,长度为n+1,其中dp[i]表示从第i个问题开始到结束能获得的最大分数。然后从后往前遍历每个i,计算两种情况的最大值。 接下来,如何实现这个呢? 在C++中,可以这样做: - 首先获取questions的大小n。 - 创建dp数组,大小为n+1。dp[n] =0。 - 然后从i=n-1到i=0遍历: - 计算如果选择解决i的话,那么next_i = i + brainpower[i] +1。如果next_i >=n的话,那么只能加0,否则加dp[next_i]。 - 得分是questions[i][0] + (next_i >=n ?0 : dp[next_i]) - 解决的话,得分是dp[i+1] - dp[i] = max(解决的得分,解决的得分) - 最后返回dp[0] 比如上面的例子,计算后的dp数组应该是: dp[4] =0 dp[3] = max(2+0, 0) =2 dp[2] = max(4+0, 2)=4 dp[1] = max(4+0,4)=4 dp[0] = max(3+2,4) =5 所以正确。 那这个方法的时间复杂度是O(n),空间复杂度是O(n)。对于题目中的约束条件来说,应该是可行的。题目中的n可能有多大呢?假设是1e5的话,这样的方法应该可以。但要看题目中的具体限制。过原题可能来自leetcode,例如题目编号可能对应某个具体的题目。比如,LeetCode 2140题目就是这个题目。根据LeetCode的测试用例,这个方法是可行的。 因此,最终的C++代码大概结构是: class Solution { public: long long mostPoints(vector<vector<int>>& questions) { int n = questions.size(); vector<long long> dp(n+1, 0); for(int i =n-1; i>=0; --i){ int next = i + questions[i][1] +1; long long solve = questions[i][0] + (next >=n ?0 : dp[next]); long long skip = dp[i+1]; dp[i] = max(solve, skip); } return dp[0]; } }; 需要注意的点: - 使用long long类型,因为分数可能很大,会超过int的范围。 - 正确计算next的值,并且处理越界的情况。 这样应该就能解决问题了。</think>### 问题分析 我们需要在按顺序处理一系列考题时,选择解决或跳过以获得最高分数。每次解决问题会获得分数,但必须跳过后续若干问题。动态规划是解决这类问题的有效方法。 ### 方法思路 1. **状态定义**:定义 `dp[i]` 表示从第 `i` 题开始到末尾能获得的最大分数。 2. **状态转移**: - **解决当前题**:获得 `points[i]`,并跳过 `brainpower[i]` 题,下一个可处理的是 `i + brainpower[i] + 1`。 - **跳过当前题**:直接处理下一题 `i+1`。 - 取两种情况的较大值更新 `dp[i]`。 3. **初始化**:`dp[n] = 0`(末尾无题可解)。 4. **逆序计算**:从后向前递推,确保后续状态已计算。 ### 解决代码 ```cpp #include <vector> #include <algorithm> using namespace std; class Solution { public: long long mostPoints(vector<vector<int>>& questions) { int n = questions.size(); vector<long long> dp(n + 1, 0); // dp[i]表示从第i题开始能获得的最大分数 for (int i = n - 1; i >= 0; --i) { int next = i + questions[i][1] + 1; // 解决当前题后,下一个可处理的题号 long long solve = questions[i][0] + (next >= n ? 0 : dp[next]); long long skip = dp[i + 1]; dp[i] = max(solve, skip); } return dp[0]; } }; ``` ### 代码解释 1. **初始化**:`dp` 数组长度为 `n+1`,初始值为 `0`。 2. **逆序遍历**:从最后一题开始向前处理。 3. **状态转移**:计算解决当前题跳过当前题的得分,取最大值更新 `dp[i]`。 4. **返回结果**:`dp[0]` 即为从第一题开始处理的最大得分。 该方法时间复杂度为 $O(n)$,空间复杂度为 $O(n)$,能高效处理大规模输入。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值