csp复习
前言
马上又是一年新赛季
在此先挖个坑,以后慢慢填
例题什么的以后补
高效进阶
基础算法
递推算法
简介
- 从已知条件出发推到结果,称为顺推
- 从问题结果逐步推到已知条件,称为逆推(如果加入记忆化,也可以做到顺推复杂度)
关键点
- 定义状态
- 初始化
- 递推式
- 答案结果
例子
题目描述
将整数 \(n\) 分成 \(k\) 份,且每份不能为空,任意两个方案不相同(不考虑顺序)。
例如:\(n=7\),\(k=3\),下面三种分法被认为是相同的。
\(1,1,5\);
\(1,5,1\);
\(5,1,1\).
问有多少种不同的分法。
解决
- 设 \(f[i][j]\) 为\(i\)分为\(j\)分的方案数
- 1.\((j>i)\)
没法分啊此时\(f[i][j]=0\);
2.$(j=i) $ \(f[i][j]=1\);
3.\((j<i)\)- 将第j份放上1,转化为\(f[i-1][j-1]\)
- 将每一份减1,转化为\(f[i-j][j]\)
练习题
贪心
简介
- 贪心选择性
每次做出的选择仅依赖于从前做出的选择,不依赖于未做出的选择。 - 最优子结构
一个问题的全局最优解包含了其子问题的最优解。
证明
- 反证法
判断反命题的正确性 - 归纳法
例子
题目描述
一件衣服在自然条件下用一秒的时间可以晒干 \(a\) 点湿度。抠门的熊大妈只买了一台烘衣机 。使用用一秒烘衣机可以让一件衣服额外烘干 \(b\) 点湿度(一秒晒干 \(a+b\) 湿度),但在同一时间内只能烘一件衣服。现在有 \(n\) 件衣服,第 \(i\) 衣服的湿度为 \(w_i\)(保证互不相同),要你求出弄干所有衣服的最少时间(湿度为 \(0\) 为干 )。
解决
如果没有烘干机,晾干所有衣服的时间就是湿度最大的衣服晾干所用时间,所以贪心来想每次用烘干机烘干湿度最大的衣服必定是最优的。
练习题
二分算法
简介
如果我们做到一道题难以求解,但是答案具有单调性可以用二分(如题目中给出了最大值最小)。二分可以看成暴力搜查找答案的优化。
二分的写法
避免奇怪的边界问题,顺便减小常数。
- 整数域上的二分答案求最大值:
while(l<=r)
{
int mid=(l+r)>>1;
if(a[mid]>=ans) ans=mid,l=mid+1;
//l=mid+1是为了避免死循环:
//当r=l+1时,如果答案为l,那么mid始终会向下取整到l,l也始终等于mid,即l的值无法改变
else r=mid-1;
}
- 整数域中二分答案求最小值:
while(l<r)
{
int mid=(l+r)>>1;
if() l=mid+1;
else r=mid;
}
- 实数域上的二分
while(r-l>eps)
{
double mid=(l+r)/2;
//不能用>>1代替/2
if() l=mid;
else r=mid;
}
例子
题目描述
对于给定的一个长度为 \(N\) 的正整数数列 \(A_{1\sim N}\),现要将其分成 \(M\)(\(M\leq N\))段,并要求每段连续,且每段和的最大值最小。
解决
出现了最大值最小,考虑用二分。
设每段和的最大值为S,则每段和都小于等于S,所以我们每次二分答案S,判断其所划分的段数,具体的:
- 如果按每段小于等于S划分,划分出的段数小于等于M,则证明每段和的最大值的最小值小于等于S。
- 如果按每段小于等于S划分,划分出的段数大于M,则证明每段和的最大值的最小值大于S。
练习题
深搜
简介
DFS 与“递归”“栈”密切相关,递归实现较常用。
大概是想就是将要搜索的目标分成若干「层」,每层基于前几层的状态进行决策,直到达到目标状态。
剪枝
如果不加优化,搜索树的复杂度大多是指数级的。为了在规定时间解决问题就要进行剪枝
- 优化搜索顺序
不同的搜索顺序会产生不同的搜索树形态,规模也不同 - 排除等效冗余
部分分支到达的结果是等效的,那么我们只对其中一条进项搜索 - 可行性剪枝
如果发现无法到达递归边界就回溯 - 上下界剪短枝
题目中通常会给定一个范围,根据所给定的区间进行剪枝 - 最优性剪枝
如果当前花费的代价已经超过最优的答案,那么此时的分支已经没有必要继续搜索 - 记忆化
记录每个状态的搜索结果,在重复遍历一个状态时直接返回相应的结果
练习题
广搜
简介
所谓宽度优先。就是每次都尝试访问同一层的节点。 如果同一层都访问完了,再访问下一层。
板子
viud bfs(int s)
{
queue<int> q;
int v[N];
int fa[N];
memset(v, 0, sizeof(v));
memset(fa, 0, sizeof(fa));
q.push(s);
v[s] = 1;
while (q.size())
{
int u = q.front();
q.pop();
if ()
{
// 输出答案
break;
}
for (int i = 1; i <= n; i++)
{
if ()
{
q.push();
v[] = q;
fa[] = p;
}
}
}
}
大概是这个样子
字符串算法
字符串处理
string 常见操作
| 操作 | 意义 |
|---|---|
| s.insert(pos,s2) | 在s下标为pos的元素前插入s2 |
| s.substr(pos,n) | 返回s从下标pos起的n个字符 |
| s.erase(pos,n) | 删除s下标pos起的n个字符 |
| s.replace(pos,n,s2) | s下标pos起的n个字符替换为s2 |
| s.find(s2.pos) | 删除s下标pos起查找s2第一次出现的位置 |
hash和hash表
hash算法简介
通过一个hash函数,将(字符串,较大的数)转化为能够用变量表示或是直接就可以作为数组下标的树,通过hash值可以实现快速查找和匹配。
一维hash
二维hash
KMP
Tire树
AC自动机
图论
并查集
最小生成树
最短路
强连通分量
数据结构
二叉堆
树状数组
RMQ问题
线段树
LCA问题
倍增问题
动态规划
背包DP
区间DP
数位DP
树形DP
状压DP
单调队列
数学基础
矩阵快速幂
快速幂
int quickpow(int a,int b,int n)
{
int ans=1;
while(b)
{
if(b%2==1)
ans=ans*a%n;
a=a*a%n;
b/=2;
}
return ans;
}
矩阵乘法
设矩阵A大小为\(n*r\),矩阵B大小为 \(r*m\),设\(C=A*B\),则C大小为\(n*m\)
质数与约数
同余问题
组合数学
博弈论
期望问题
金牌导航
本文来自博客园,作者:流氓兔LMT,转载请注明原文链接:https://www.cnblogs.com/-include-lmt/p/18984553

浙公网安备 33010602011771号