2023 国庆CSP-J刷题营笔记整合

Day1

枚举与搜索


枚举

例1:洛谷P1008

  • 考虑枚举所有三位数,可过,然而时间复杂度高,容易枚举没写不符合题目的答案
  • 可找到1:2:3条件来枚举

例2:洛谷P1217

  • 枚举a-b中所有回文质数,TLE
  • 枚举a-b中所有质数,TLE*2
  • 枚举回文数(正解)
枚举回文数:
1. 枚举前一半(总结规律可以发现如果为质数第一位只能为1 3 7 9)
2. 判断位数奇偶
	eg:
	枚举了前一半137
	奇数:137731
	偶数:13731
  • 记录数量,AC

例3:洛谷P1102
双指针算法

感觉类似莫队,就是不断缩小范围直到最小区间

#include<bits/stdc++.h>
using namespace std;
#define int long long
int ans;
signed main(){
	int a[1000050],n;
	a[0]=-10000000;
	int vr,vl;
	cin>>n>>vl;
	vr=vl;
	for(int i=1;i<=n;i++) cin>>a[i];
	sort(a+1,a+n+1);
	int j1=0,j0=0;
	for(int i=1;i<=n;i++){
		
		while(a[i]-a[j0]>vr) j0++;
		while(a[i]-a[j1]>=vl) j1++;
		if(j0<j1){
			ans+=j1-j0;
			//cout<<j1<<' '<<j0<<"\n";
		}
	}
	cout<<ans;
	return 0;
}
/*
4 1 1
1 1 2 3 
*/

搜索

搜索本质也是枚举,差别在于代码实现

全排列模型
  • DFS枚举全排列
  • STL大法好algorithm库的next_permutation(p+1,p+n+1)函数,且当p为字典序最大的排列时,它会返回0,否则会返回1

两种方法各有优劣,前者方便减枝,后者实现更为方便。

例1:洛谷P1219

  • 枚举全排列,结束

二进制模型、集合/正整数划分模型.......

剪枝

  1. 变换搜索顺序洛谷P1074
  2. 可行性剪枝
  3. 物品排序后搜索(没有什么道理,却能使搜索变得十分优秀。)
  4. 最优性剪枝(01背包问题,但是DFS)


Day2

数据结构

链表:

单向链表:

模版:洛谷B3631

前项星:

本质:前项星是由多个单项链表组成,维护链头数组,然后可以支持每个点加边。

struct nod
{
	int next,to;
}e[xx*2];
int cnt,h[xx];
void add(int x,int y){
	cnt++;
	e[cnt]={h[×],y};
	h[×]=cnt;
}
void dfs(int x,int y){
	for(int i=h[×];i;i=e[i].next)
		dfs(e[i].to,x);
}

洛谷P3916


双向链表:

模版:洛谷P1160

就比单向链表多了个后继而已=_=


之所以重要,是因为它其实就是递归的逻辑结构,先进后出

STL:

stack<int>stk;
stk.push(1);
stk.pop();
cout<<stk.top()<<"\n";
cout<<stk.size()<<"\n";

洛谷B3614

单调栈

  • 始终保持站内元素为单调的
  • 比较下标优先
输入序列:1 4 2 3 5
栈内变化:
5
5 3
5 3 2
5 4
5 4 1

用来求第一个大于某个元素的下标

洛谷P5788


动态数组vector

顾名思义,它的容量是变化的,是动态的数组

当内部使用的容量到达了它的上界,他的容量就会翻2倍。

如:

a={}          a.push_back(1)  0
a={1}         a.push_back(2)  1
a={1,2}       a.push_back(3)  2
a={1,2,3}     a.push_back(4)  4
a={1,2,3,4}   a.push_back(5)  8
a={1,2,3,4,5}                 16
     ...            ...

我们也可以分配内存a.resize()

也可以释放内存vector<int>().swap(a),默认是占24字节


队列

就是模拟现实中的排队的队列,先进先出

洛谷B3616

双端队列(deque)

就是两个头相对的队列合一块,STL是支持随机访问

然而空间是特别大的,默认分配内存有80个字节,1e6个内存总共80多MB

单调队列

洛谷P1886

原理跟单调栈类似,就是可以取队首元素可pop队首了


一种完全二叉树,可以维护一个最小值或最大值,插入数值时间复杂度为O(log2n),删除同

洛谷P3378

对顶堆

一个序列,我们每次加入一个元素,或者进行询问。

维护一个初始指针i=0,每次询问的时候将i=i+1然后询问第i小的值是多少。

洛谷P1801

哈夫曼树

洛谷P1090

  • 每个数贡献的次数是他到根的边数。
  • 数大的贡献较少,即经过的边数较少。
  • 如果把边顺次标号为 0,1,则每个叶子到根的一个字符串称为哈夫曼编
    码。


Day3

动态规划

简单DP

洛谷P1216

1.正着递推

  • 可以从顶往下推
  • f[i][j]=max(f[i-1][j],f[i-1][j-1])+a[i][j];

2.倒着递推

  • 从下往上推
  • f[i][j]=max(f[i+1][j],f[i+1][j+1])+a[i][j];

背包DP

给定n个价值为Vi,体积为Wi的物品,你有一个容积为M的背包,求怎样装物品才能使价值之和最大。

采药

洛谷P5664

洛谷P5665

区间DP

洛谷P1430

  • f[l][r]表示还剩下[l,r]的数,我们先手获得的最大价值==后手获得的最大价值
  • 可以直接深搜


Day4

图论

概念

树:

  • 无环
  • 连通
  • U,V之间唯一一条路

有向无环图(DAG):

  • 可以进行拓扑排序
  • 可以进行DP
  • 都为二分图

树的储存:

  • 记录每个点的父亲
  • 每个点存他的儿子
  • 当成图来存

树的名词:

  • 子树
  • 深度
  • 路径
  • 直径:距离最大的一对点之间的距离为多少
  • 重心:以一个点为根,左子树的点和右子树的相等则称该点为一棵树的重心

二叉树

  • 每个点最多有两个儿子
  • 二叉树的先序遍历为它的DFS顺序

完美二叉树:每个点都有两个儿子

完全二叉树:点n的父亲为n/2,点的儿子为2n、2n+1


DAG最短/长路

直接BFS即可

序:

  • 传递性(a>=b,b>=c,a>=c)
  • 自反性(a<=b,b<=a,a=b)
  • 反对称性(a+b=c,c+b≠a)

正序:所有序都可比较

偏序:不是所有序都可比较,但是满足序的三个性质

DAG所有点默认都是偏序

二分图

染色(把一个图染成黑白两色,让着图边两端颜色都不同):只需BFS一遍即可



Day5

贪心

就是局部最优解,看哪个最好选哪个

正确性证明:

  1. 数学归纳法

例1:

  • 定义一个函数f[i]表示取i个线段,最右端最小是多少
  • 变换过程中最优解不变

例2:

  • f[i]:1~i时间前有多少教师
  • g[i]:1~i时间最多的同时讲座的数量
  • h[i]=i时间同时讲座的数量
  • f[0]=0=g[0]
  • 往i区间里放,f[i-1]=g[i-1]>=h[i-1]
  • 能放得进去,f[i-1]=f[i],g[i-1]=g[i]>h[i]
  • ∴f[n]=g[n]

2.归纳法

3.交换论证

  • 任何最优解都可以可以变成贪心的最优解,
  • 变换过程中最优解不变

例题:国王游戏


数学

矩阵

矩阵乘法

省略

矩阵加速递推

  • f1=f2=0
  • fn=7fn1+6fn2+5n+4×3n
  • fn

高斯消元

特点:

  • 两方程互换,解不变;
  • 一方程乘以非零数 k,解不变;
  • 一方程乘以数 k 加上另一方程,解不变。

例:

{7x1+8x2+9x3=134x1+5x2+6x3=12x1+2x2+3x3=11

  • 7 8 9==13 → 1 0 04
  • 4 5 6==12 → 0 1 05
  • 1 2 3==11 → 0 0 16

取模(mod)

1001mod9

:模运算下的等价

逆元

定义

  • 假设p是一个质数,且(a,p)=1,ab=1(modp)b
  • b类似于a的倒数?
  • 也就是说,乘上—个b和除以一个a的效果是一样的b称作a的逆元,记作b=a1
  • c/a=ca1(modp)

  • 费马小定理
  • 如果p为质数,且(a,p)=1;
  • ap1(1mod9)

其他

埃拉托斯特尼筛法

  • 求1~n所有素数
  • O(nlogn)
  • 从小到大枚举数把他的倍数筛去

卡特兰数:

1,1,2,5,14

公式:

Hn=(2nn)(2nn1)

  • 只要让你输出单个数字的题,暴力程序发现前几个结果为上面的数列
  • 可以试着直接输出卡特兰数。


Day6

分治

  • 分而治之,就是把一个复杂问题分解为多个简单的子问题来解决
  • 限制为复杂问题要可分

应用:

归并排序:

基本流程:

sort(l,r);
mid
sort(l,mid);
sort(mid+1,r);
marge(l,mid,r);

逆序对

基本流程:

solve(l,r);
mid
ans+=solve(l,mid);
ans+=solve(mid+1,r);
void solve:
	a    b
	a[i]>b[j]

区间max之和、最大字段和....

时间复杂度:

最大字段和:T(n)=2T(n/2)+O(n)=O(nlogn)

区间max之和:T(n)=2T(n/2)+O(1)

例题:
洛谷P1966


二分

二分查找

简介

  • 一种查找数组元素的方法
  • 数组必须有序
  • 时间复杂度O(log(n))

STL

  • lower_bound:找到数组中第一个大于等于x的下标,返回一个地址
  • upper_bound:用法同lower_bound
  • binary_search:二分查找一个元素,返回bool值

板子:洛谷P2249

例题:洛谷P1102

  • 可以使用第一天的双指针算法

  • 排序后也可以二分查找


二分答案

简介:

  • 对答案进行二分查找

  • 要有一个明确的(答案)界限,如2 1 3 5 6可以二分(界限为4)

例题:洛谷P1873
洛谷P2440
洛谷P1024
洛谷P2678

while(l<=r){
	ull mid=(r+l)/2;//l+(r-l)/2或l+r>>1
	if(check(mid)){
		l=mid+1;
	}else{
		r=mid-1;
	}
}
cout<<r;

分数规划

oi-wiki

简介:

  • 每种物品有两个权值 a 和 b,选出若干个物品使得 ab最小/最大。

  • 假设我们要求最大值。二分一个答案 mid,然后推式子(为了方便少写了上下界):

  • ai×wibi×wi>midai×wimid×biwi>0wi×(aimid×bi)>0

  • 那么只要求出不等号左边的式子的最大值就行了。如果最大值比 0 要大,说明 mid 是可行的,否则不可行。

  • 求最小值的方法和求最大值的方法类似.


倍增

树上祖先:

  • f[i][j]为i往上跳2j
  • f[i][j]=f[f[i][j-1]][j-1]
  • (↑的意思:跳2j步,需要跳2j1+2j1步)

上面就是倍增的思想

LCA

  • 求树上两个点最近的公共祖先

  • 暴力一步一跳到自己一级祖先容易超时

  • 可以用倍增思想来跳



作者:dienter

posted @   dienter  阅读(35)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示