Q1 给小朋友们分糖果I
-
解题思路:
- 来一点暴力震撼
- 三重循环枚举三个小朋友可能取的糖果[0, limit]
- 如果三个小朋友取到的糖果总数刚好是n,答案加1
-
解题代码:
class Solution {
public:
int distributeCandies(int n, int limit) {
int ans = 0;
for(int i = 0; i <= limit; i++)
{
for(int j = 0; j <= limit; j++)
{
for(int k = 0; k <= limit; k++)
{
if(i + j + k == n)
ans += 1;
}
}
}
return ans;
}
};
- On^2的做法:
class Solution {
public:
int distributeCandies(int n, int limit) {
int ans = 0;
for(int i = 0; i <= limit; i++)
{
for(int j = 0; j <= limit; j++)
{
int k = n - i - j;
if(k >= 0 && k <= limit)
ans += 1;
}
}
return ans;
}
};
Q2 给小朋友们分糖果II
-
解题思路1:
- 设三个小朋友分到的糖果数分别为a、b、c
- 枚举第一个小朋友分到的糖果数a,问题变成 b + c = n - a,b和c有多少组解,只要判断b的取值范围就可以
- b本身满足 0 <= b <= limit
- 又因为c也要满足0 <= c <= limit,因此 0 <= n-a-b <= limit,解得 n-limit-a <= b <= n-a,因此 max(0, n-limit-a) <= b <= min(limit, n-a),b可以取的值个数就是max(0, min(limit, n-a) - max(0, n-limit-a) + 1)
-
解题代码:
class Solution {
public:
long long distributeCandies(int n, int limit) {
long long ans = 0;
for(int a = 0; a <= limit; a++)
ans += max(0, min(n-a, limit) - max(0, n-limit-a) + 1);
return ans;
}
};
-
解题思路2:
- 容斥原理
- 答案 = 全部的方案数 - 3 * 有一个小朋友大于limit的方案数(A、B、C) + 3 * 有两个小朋友大于limit的方案数(AB、AC、BC) - 有三个小朋友大于limit的方案数
- 方案数怎么求:
- 全部的方案数,相当于把n个小球和2个挡板放到n+2的位置上,2个挡板共有C(n+2, 2)种方案
- 有一个小朋友大于limit的方案 相当于把n - (limit + 1)和 2个挡板进行放置,2个挡板有C(n - (limit+1) + 2, 2)种方案
- 有两个小朋友大于limit的方案 相当于把n - 2 * (limit + 1)和 2个挡板进行放置,2个挡板有C(n - 2 * (limit+1) + 2, 2)种方案
- 有三个小朋友大于limit的方案 相当于把n - 3 * (limit + 1)和 2个挡板进行放置,2个挡板有C(n - 3 * (limit+1) + 2, 2)种方案
-
解题代码:
class Solution {
public:
long long distributeCandies(int n, int limit) {
long long ans = 0;
auto func = [&](long long num) -> long long
{
if(num < 0)
return 0;
return num * (num - 1) / 2;
};
return func(n+2) - 3 * func(n - (limit + 1) + 2) + 3 * func(n - 2 * (limit + 1) + 2) - func(n - 3 * (limit + 1) + 2);
}
};
Q3 重新排列后包含指定子字符串的字符串数目
-
解题思路:
- 记忆化搜索
- 定义dfs(i, l, e, t),i表示[0, i]范围的子字符串,l,e,t分别表示需要的l,e,t字符的数量
- 状态转移:
- 当前位置选择l,e,t之外的字符:23 * dfs(i-1, l, e, t)
- 当前位置选择l :dfs(i-1, 0, e, t)
- 当前位置选择e:dfs(i-1, l, max(e-1, 0), t)
- 当前位置选择t:dfs(i-1, l, e, 0)
- dfs(i, l, e, t) 的值为上面四项的和
- 递归入口:dfs(n-1, 1, 2, 1)
-
解题代码:
class Solution {
public:
int stringCount(int n) {
if(n < 4)
return 0;
const int MOD = 1e9+7;
long long f[n][2][3][2];
memset(f, -1, sizeof(f));
function<long long(int, int, int, int)> dfs = [&](int i, int lcnt, int ecnt, int tcnt) -> long long
{
if(i < 0)
return lcnt == 0 && ecnt == 0 && tcnt == 0 ? 1 : 0;
if(f[i][lcnt][ecnt][tcnt] != -1)
return f[i][lcnt][ecnt][tcnt];
long long &ans = f[i][lcnt][ecnt][tcnt];
ans = 0;
//随便选
ans = (ans + 23 * dfs(i-1, lcnt, ecnt, tcnt)) % MOD;
//作为leet中的一个字符来选
ans = (ans + dfs(i-1, 0, ecnt, tcnt)) % MOD;
ans = (ans + dfs(i-1, lcnt, max(ecnt-1, 0), tcnt)) % MOD;
ans = (ans + dfs(i-1, lcnt, ecnt, 0)) % MOD;
return ans;
};
return dfs(n-1, 1, 2, 1);
}
};
-
解题思路2:
-
同样可以使用容斥原理
-
总共有26 ^ n个字符串,减去不含leet的字符串个数
-
不含leet的字符串需要至少满足下面三个条件中的一个:
- 不含l
- 不含t
- 不含e或恰好包含一个e
-
至少满足一个条件:
- 不含l:25^n
- 不含t:25^n
- 不含e:25^n
- 恰好包含一个e:n * 25^(n-1)
-
至少满足两个条件:
- 不含l和t:24^n
- 不含l且e的个数不足两个:24^n + n * 24^(n-1)
- 不含t且e的个数不足两个:24^n + n * 24^(n-1)
-
满足三个条件:23^n + n * 23^(n-1)
-
最终答案 = 总方案数 - 至少满足一个条件 + 至少满足两个条件 - 满足三个条件
-
用快速幂计算幂
-
-
解题代码:
class Solution {
public:
const int MOD = 1e9+7;
long long myPow(int a, int n)
{
if(n == 0)
return 1;
if(n & 1)
return (a * myPow(a, n-1)) % MOD;
long long temp = myPow(a, n/2);
return (temp * temp) % MOD;
}
int stringCount(int n) {
return ((myPow(26, n) -
(myPow(25, n) * 3 + n * myPow(25, n-1)) +
(myPow(24, n) * 3 + 2 * n * myPow(24, n-1)) -
(myPow(23, n) + n * myPow(23, n-1))) % MOD + MOD) % MOD;
}
};
Q4 购买物品的最大开销
- 题目链接
- 解题思路:
- 用一个小根堆维护当前可取的物品
- 每次都取价值最小的物品,并将其左侧物品(如果有)加入到堆中
- 解题代码:
class Solution {
public:
long long maxSpending(vector<vector<int>>& values) {
//最大开销
long long ans = 0;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> pq;
int m = values.size();
int n = values[0].size();
for(int i = 0; i < m; i++)
pq.push({values[i][n-1], i * n + n-1});
long long d = 1;
while(!pq.empty())
{
auto [val, idx] = pq.top();
pq.pop();
ans += val * d;
int x = idx / n;
int y = idx % n;
if(y != 0)
pq.push({values[x][y-1], idx-1});
d += 1;
}
return ans;
}
};