小红书2019.8.18笔试(超详细的解法!!!)

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(icoin)(coincoins)

其中 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(icoin)+f(i)(也就是将所有的商品价格遍历)。举个例子,假设我们现在求金额为8的组合数,那么我们只需要知道金额为8-2=68-3=58-5=3的组合数是多少然后加起来即可(相当于在653的基础上又添加了一个数)。

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

解题思路

使用pythonsplit,然后判断字符串是不是空,如果不是空的话,添加到结果数组的前面。

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(i1),f(i2)+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;
}

如有问题,希望大家指出!!!

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值