6.17 note
翻转矩阵的贪心
//1.行翻转:确保最高位为1
//2.列反转: 计数,让除最高位外 多数变为1
返回二维空数组
return {};
数学题
const int MOD = 1e9 + 7;
class Solution {
int fast_pow(uint64_t base, int exp) {
uint64_t result = 1;
while (exp > 0) {
if (exp % 2 == 1) {
result = (result * base) % MOD;
}
base = (base * base) % MOD;
exp /= 2;
}
return result;
}
int comb(int n, int k) {
if (k > n)
return 0;
if (k == 0 || k == n)
return 1;
uint64_t numerator = 1;
uint64_t denominator = 1;
for (int i = 0; i < k; ++i) {
numerator = (numerator * (n - i)) % MOD;
denominator = (denominator * (i + 1)) % MOD;
}
return (numerator * fast_pow(denominator, MOD - 2)) % MOD;
}
public:
int countGoodArrays(int n, int m, int k) {
uint64_t res = m;
res = ((res * fast_pow(m - 1, n - k - 1)) % MOD) * comb(n - 1, k);
return res % MOD;
}
};
1. 先看 “全局” 小设定: const int MOD = 1e9 + 7;
这是给结果 “取模” 用的。因为题目里结果可能很大,得按照题目要求(一般竞赛题会要求对 10^9 + 7 取模)把结果限制在合理范围,避免数值爆炸、也符合题目输出要求。
2. 类和方法整体作用
这是一个叫 Solution 的类,里面封装了几个函数,最终用 countGoodArrays 解决 “统计恰好有 K 个相等相邻元素的数组数目” 问题。可以理解成:给定数组长度 n 、数的范围 m (每个位置选 1~m 的数)、需要恰好 k 对相邻相等的情况,计算有多少种这样的数组。
3. 逐个函数拆解
(1) fast_pow :快速算 “幂取模”
int fast_pow(uint64_t base, int exp) {
uint64_t result = 1;
while (exp > 0) {
if (exp % 2 == 1) { // 如果指数是奇数,先乘一次 base
result = (result * base) % MOD;
}
base = (base * base) % MOD; // 底数平方,指数减半的准备
exp /= 2; // 指数除以 2(整数除法,自动去掉余数)
}
return result;
}
- 干啥的:高效计算 base^exp % MOD 。比如算 3^{10},普通方法要乘 10 次,但快速幂通过 “指数二分”,只需要几次循环就能算完(像 3^{10} = (3^5)^2 = ((3^2)^2 \times 3)^2 这样拆)。
- 为啥用:计算大指数的幂时,直接硬算太慢,快速幂能大幅减少计算次数,还能结合 % MOD 避免数值太大。
(2) comb :算组合数 C(n, k)(即从 n 个里选 k 个的方案数)
int comb(int n, int k) {
if (k > n) return 0; // 选的比总数还多,不可能,返回 0
if (k == 0 || k == n) return 1; // 选 0 个或者全选,只有 1 种方案
uint64_t numerator = 1; // 分子:n*(n-1)*...*(n-k+1)
uint64_t denominator = 1; // 分母:k*(k-1)*...*1
for (int i = 0; i < k; ++i) {
numerator = (numerator * (n - i)) % MOD;
denominator = (denominator * (i + 1)) % MOD;
}
// 组合数公式:C(n,k) = 分子 / 分母 ,但这里用 “费马小定理” 转成乘法
return (numerator * fast_pow(denominator, MOD - 2)) % MOD;
}
- 核心逻辑:组合数公式是 C(n,k) = \frac{n!}{k!(n - k)!} ,但直接算阶乘容易溢出,所以这里拆成 “分子乘、分母乘”,最后用 费马小定理 把除法转成 “乘以分母的模逆元”(因为 MOD 是质数,所以逆元是 denominator^(MOD-2) % MOD )。
- 举个栗子:算 C(5,2) ,分子是 5 \times 4 = 20 ,分母是 2 \times 1 = 2 ,结果就是 20 / 2 = 10 ;代码里会用 fast_pow(2, MOD-2) 算出 2 的逆元,再用 20 * 逆元 % MOD 得到结果。
(3) countGoodArrays :最终计算符合条件的数组数目
int countGoodArrays(int n, int m, int k) {
uint64_t res = m;
res = ((res * fast_pow(m - 1, n - k - 1)) % MOD) * comb(n - 1, k);
return res % MOD;
}
- 思路对应题目分析:
- 题目里说 “每个位置选数,有 1~m 共 m 种选择”,但要恰好 k 对相邻相等。可以理解成:
- 第一个数随便选,有 m 种可能(对应代码里 res = m )。
- 剩下的位置里,需要选 k 个位置让它和前一个数相等(这一步用 comb(n - 1, k) 算有多少种选法);剩下的 (n - 1 - k) 个位置 必须和前一个数不同,每个位置有 m - 1 种选法(所以用 fast_pow(m - 1, n - k - 1) 算这些位置的总方案数)。
- 把这些乘起来: m * (m-1)^(n - k - 1) * C(n-1, k) ,就是最终符合条件的数组总数。
- 举个栗子:假设 n=3 , m=2 , k=1 (数组长度 3,数选 1/2,恰好 1 对相邻相等)
- 第一个数:2 种选法(比如选 1 或者 2)。
- 剩下 n-1=2 个位置里选 k=1 个位置让它和前一个相等 → C(2,1)=2 种选法(比如位置 2 相等、位置 3 不等;或者位置 3 相等、位置 2 不等 )。
- 剩下 n - k - 1 = 3 - 1 - 1 = 1 个位置必须 “不等”,每个位置有 m-1=1 种选法 → 1^1=1 。
- 总数就是 2 * 1 * 2 = 4 ,可以手动验证是否符合预期~
4. 整体流程总结
1. 用 fast_pow 快速算幂取模,解决大指数计算问题。
2. 用 comb 算组合数,通过 “分子分母分别乘 + 费马小定理转逆元” 避免阶乘溢出。
3. 最后 countGoodArrays 把这些组合起来:先定第一个数的选法,再算 “选哪些位置相邻相等”,以及 “剩下位置不相等的选法”,三者相乘就是答案。
这样拆解下来,应该能明白每一步的作用啦~ 本质是把题目里的组合逻辑,用数学上的 “组合数” + “快速幂” 转化成代码,高效算出结果 。
RAII
RAII(Resource Acquisition Is Initialization,资源获取即初始化 )是 C++ 编程技术/范式
核心是将资源(堆内存、线程、套接字、文件、锁等有限资源 )的生命周期与对象生命周期绑定
借栈上局部变量自动析构,保证资源一定被释放
消除泄漏、确保异常安全,具体:
- 资源绑定:构造对象时获取资源(如构造函数里开文件、锁互斥量 )。
- 自动释放:对象生命周期结束(离开作用域等 ),析构函数自动释放资源(关文件、解锁 ),哪怕程序异常也会执行。
- 典型应用:智能指针( unique_ptr / shared_ptr 管内存 )、
锁管理( lock_guard 管锁 )、
文件流( ofstream / ifstream 管文件 ) ,
让资源管理更简洁、安全,少手动释放出错风险。
解码
class Solution {
public:
string freqAlphabets(string s)
{
int n = s.size();
string ret;
for(int i = 0; i < n; )
{
if(i + 2 < n && s[i+2] == '#')
{
//预判断
string ss = string(1, s[i]) + s[i+1];
int tmp = stoi(ss);
ret += 'a' + tmp - 1;
i += 3;
}
else
{
int tmp = s[i] - '0';
ret += 'a' + tmp - 1;
i++;
}
}
return ret;
}
};
合作过的导演和演员
SELECT
actor_id,
director_id
FROM
ActorDirector
GROUP BY
actor_id,director_id
-- 选出合作过的导演和演员
HAVING COUNT(*)>=3
-- 筛选出合作次数大于等于3的组合