0x01
解题思路
典型的动态规划问题,我们定义函数 f ( i ) f(i) f(i)表示金额为 i i i的时候输出的所有组合数,那么
- f ( i ) = f ( i ) + ∑ f ( i − c o i n ) ( c o i n ∈ c o i n s ) f(i) = f(i) +\sum f(i-coin)(coin\in coins) f(i)=f(i)+∑f(i−coin)(coin∈coins)
其中
c
o
i
n
coin
coin表示商品价格,而
c
o
i
n
s
coins
coins表示所有商品的价值,那么
f
(
i
)
f(i)
f(i)此时的组合数个数,显然就是将
∑
f
(
i
−
c
o
i
n
)
+
f
(
i
)
\sum f(i-coin)+f(i)
∑f(i−coin)+f(i)(也就是将所有的商品价格遍历)。举个例子,假设我们现在求金额为8
的组合数,那么我们只需要知道金额为8-2=6
、8-3=5
和8-5=3
的组合数是多少然后加起来即可(相当于在6
、5
、3
的基础上又添加了一个数)。
str = list(input().split())
amount = int(str[0])
coins = list(map(int, str[1].lstrip("[").rstrip("]").split(",")))
dp = [0] * (amount + 1)
dp[0] = 1
for coin in coins:
for i in range(amount - coin + 1):
if dp[i]:
dp[i + coin] += dp[i]
print(dp[amount])
0x02
解题思路
使用python
的split
,然后判断字符串是不是空,如果不是空的话,添加到结果数组的前面。
data = list(input().split())
res = ""
for i in data:
if i != "":
res = i + res
print(res)
0x03
解题思路
和Leetcode 198:打家劫舍(最详细的解法!!!)类似。我们定义函数 f ( i ) f(i) f(i)表示第 i i i个位置包括之前元素可以得到的最大点赞数,那么
- f ( i ) = m a x ( f ( i − 1 ) , f ( i − 2 ) + d a t a [ i ] ) f(i)=max(f(i-1),f(i-2)+data[i]) f(i)=max(f(i−1),f(i−2)+data[i])
其中 d a t a [ i ] data[i] data[i]表示第 i i i本书的点赞数。
n = int(input())
data = list(map(int, input().split()))
pre, cur = [0, 0], [0, 0]
for i in data:
tmp, pre = pre[::], cur[::]
if tmp[0] + i > cur[0]:
cur[0] = tmp[0] + i
cur[1] = tmp[1] + 1
print(cur[0], cur[1])
0x04
解题思路
查找问题不难想到二分法。固定伤害的最小值是0
,最大值一定是所有血量的最大值。现在我们最难的问题就是判断给定伤害是不是合法。
对于是不是合法的问题,我们使用贪心策略,每次从血量data
中取最大值(所以使用最大堆存储血量),然后判断这个最大值可以消耗几次法术。假设最大值是pre
,伤害是mn
,法力值是m
,那么我们可以md=min(pre/mn,m)
次法术。接着我们需要将怪兽的剩余血量pre-md*mn
添加到血量数组中data
。如果中间的过程中出现t
(也就是可以攻击的次数)小于0
的情况,那么自然就不合法了。如果法力值m
消耗完了,此时我们所有data
值的和大于攻击次数t
,那么自然不合法,否则一定合法。
当伤害mn
合法的时候,那么说明>mn
的伤害一定都合法,我们只需要在[l,mn]
区间中找下一个即可;否则,我们在[mn+1,r]
区间中找。
#include <iostream>
#include <queue>
using namespace std;
bool check(int n, int t, int m, int mn, priority_queue<int> data, long long sum) {
while (!data.empty()) {
if (m) {
auto pre = data.top(); data.pop();
sum -= pre;
if (pre > mn) {
int md = min(pre / mn, m);
data.push(pre - md * mn);
sum += pre - md * mn;
m -= md;
t -= md;
} else m--, t--;
if (t < 0) return false;
} else {
if (sum > t) return false;
return true;
}
}
return true;
}
int main()
{
int n, t, m;
scanf("%d %d %d", &n, &t, &m);
priority_queue<int> q;
long long sum = 0;
for (int i = 0; i < n; ++i) {
int data; scanf("%d", &data);
q.push(data);
sum += data;
}
int l = 0, r = q.top();
while (l < r) {
int mid = l + r >> 1;
if (check(n, t, m, mid, q, sum)) r = mid;
else l = mid + 1;
}
cout << l << endl;
}
如有问题,希望大家指出!!!