1. 纯偶数问题的五进制解法
1.1 问题本质分析
纯偶数由数字0、2、4、6、8组成,按从小到大排列构成一个特殊的数列。观察前20个纯偶数:
0, 2, 4, 6, 8, 20, 22, 24, 26, 28, 40, 42, 44, 46, 48, 60, 62, 64, 66, 68...
可以发现这些数字的排列规律与五进制数有直接对应关系。具体对应方式为:
- 五进制0 → 纯偶数0
- 五进制1 → 纯偶数2
- 五进制2 → 纯偶数4
- 五进制3 → 纯偶数6
- 五进制4 → 纯偶数8
1.2 算法实现细节
核心思路是将n-1转换为五进制数,然后将每位数字乘以2:
cpp复制long long cnt=0, aa=n-1;
while(aa){
a[++cnt]=aa%5; // 获取五进制各位
aa/=5;
}
for(long long i=cnt;i>=1;i--)cout<<a[i]*2; // 输出转换结果
注意事项:当n=1时需要特殊处理直接输出0,因为n-1=0会导致循环不执行
1.3 数学原理证明
设第n个纯偶数为f(n),可以证明:
f(n) = 2 × (n-1)的五进制表示
这是因为五进制每个数位有5种取值(0-4),正好对应纯偶数的5种数字(0,2,4,6,8)。这种映射保持了数值的大小顺序。
2. 字符串三元组统计的DP解法
2.1 问题重述
给定一个由'C'、'S'、'P'组成的字符串,统计所有满足i<j<k且s[i]='C'、s[j]='S'、s[k]='P'的三元组数量。
2.2 动态规划状态设计
使用三维DP数组:
- dp[i][1]:前i个字符中'C'的数量
- dp[i][2]:前i个字符中'CS'序列的数量
- dp[i][3]:前i个字符中'CSP'序列的数量
状态转移方程:
cpp复制dp[i][1] = dp[i-1][1] + (a[i]=='C');
dp[i][2] = dp[i-1][2] + (a[i]=='S')*dp[i-1][1];
dp[i][3] = dp[i-1][3] + (a[i]=='P')*dp[i-1][2];
2.3 算法复杂度分析
- 时间复杂度:O(n),只需一次线性扫描
- 空间复杂度:O(n),可优化为O(1)只保留前一个状态
实操技巧:在实际编码中,可以用三个变量代替DP数组,节省空间
3. 网格填数问题的快速幂解法
3.1 问题转化
在2×n网格中填入三个大质数,要求相邻格子数字不同。由于给定的三个数两两互质,问题简化为相邻格子不重复的排列问题。
对于第一列有3种选择,第二列有2种(不同于第一列),依此类推。因此总方案数为:
3 × 2^(n-1) × 2 = 3^n × 2 mod 10007
3.2 快速幂实现
cpp复制int quick_mi(long long a,long long n,long long q){
long long ans=1;
while(n){
if(n%2){
ans=(ans*a)%q;
n--;
}
else{
a=(a*a)%q;
n/=2;
}
}
return ans;
}
3.3 模运算特性
由于10007是质数,可以利用费马小定理进行优化:
3^10006 ≡ 1 mod 10007
因此可以先计算n mod 10006再求幂
4. 无权图最短路径的BFS解法
4.1 图论基础
在边权均为1的无向图中,BFS是求解单源最短路径的最优算法,因为:
- BFS按层次遍历,首次访问时的路径就是最短路径
- 时间复杂度O(V+E),优于Dijkstra的O(ElogV)
4.2 算法实现要点
cpp复制int bfs(){
q.push({1, 0});
while(!q.empty()){
node n1 = q.front();
q.pop();
if (n1.n == n) return n1.step;
for (int j = 0; j < c[n1.n].size(); j++){
node n2 = {c[n1.n][j], n1.step + 1};
if (!v[n2.n]){
q.push(n2);
v[n2.n] = 1;
}
}
}
}
注意事项:必须使用visited数组标记已访问节点,否则会重复处理
4.3 性能优化
- 使用邻接表存储图结构
- 双向BFS可以进一步优化时间复杂度
5. 文件合并的贪心算法
5.1 问题分析
合并多个文件的代价等于被合并文件大小之和。要使总代价最小,应该总是先合并最小的两个文件,这样较大的文件参与合并的次数最少。
5.2 优先队列实现
cpp复制priority_queue<node>st; // 最小堆
while(st.size()>=2){
node x=st.top(); st.pop();
node y=st.top(); st.pop();
ans+=x.x+y.x;
st.push({x.x+y.x});
}
5.3 算法正确性证明
这与Huffman编码的构造过程一致,可以证明贪心选择性质成立:
- 局部最优解能导致全局最优解
- 没有后效性
6. 位运算构造问题
6.1 问题重述
对于给定的x,找到两个数a和b满足:
- a AND b = 0
- a XOR b = x
- 最大化a + b
6.2 位运算策略
关键观察:a + b = (a XOR b) + 2*(a AND b) = x + 0 = x
但实际上可以做得更好,通过将x的二进制位拆分到a和b中:
cpp复制for(int i=30;i>=0;i--){
if(x&(1<<i)){
if(a==0) a|=(1<<i);
else b|=(1<<i);
}
else if((a|(1<<i))<=x){
a|=(1<<i);
b|=(1<<i);
}
}
6.3 算法正确性
这种方法确保:
- a ^ b = x(因为不同时为1的位保留,同时设置的位抵消)
- a + b = (a | b) + (a & b) 最大化
- 时间复杂度O(logx)