NOI 大纲计划
将会对照 NOI 大纲的 提高级 内容进行刷题,每个知识点 \(2\) 到 \(5\) 题左右
您可以在 这里 看到此计划的全部源代码
成员函数与运算符重载
struct student
{
int id, score;
student(int _id = 0, int _score = 0)
{
id = _id;
score = _score;
}
};
vector <student> v;
int main()
{
v.push_back(student(1,2));
}
- 运算符重载
struct student
{
int id, score;
friend bool operator < (student a, student b)
{
if(a.score != b.score) return a.score<b.score;
return a.id<b.id;
}
}a[10];
STL 模板
- set
set<int> s;//定义
s.insert(1);//插入元素 1
s.erase(1);//删除元素 1
s.size();//元素个数
s.count(2);// 2 的个数
s.empty();
s.clear();
遍历使用 auto
for(auto it:s)
cout<<it<<' ';
其中 unordered_set
为无序 set
.
- list
待更新
- deque
待更新
- priority_queue
//升序队列
priority_queue <int,vector<int>,greater<int> > q;
//降序队列
priority_queue <int,vector<int>,less<int> >q;
q.empty();
q.top();
q.push();
- multiset
set
不可以插入重复数据,而 multiset
可以
- map
当数组用.
- multimap
map
不允许键值对重复,但 multimap
允许。
- pair
不介绍.
因为我懒
- tuple
相当于结构体.
数据结构
此部分 不全部介绍 .
- ST 表
ST 表是用于解决 可重复贡献问题 的数据结构。
除 RMQ 以外,还有其它的“可重复贡献问题”。例如“区间按位和”、“区间按位或”、“区间 GCD”,ST 表都能高效地解决。其实只要线段树/树状数组写得熟,根本不用它
ST 表基于 倍增 思想,可以做到 \(O(n \log n)\) 预处理, \(O(1)\) 回答每个询问。但是不支持修改操作。
const int N = 100000 + 7;
int n,m;
int maxx[N][21];
int calc(int l,int r)
{
int mid = log2(r-l+1);
return max(maxx[l][mid],maxx[r-(1<<(mid))+1][mid]);
}
int main()
{
read(n);read(m);
for(int i=1;i<=n;i++)
read(maxx[i][0]);
int k = log(n)/log(2) + 1;
for(int j=1;j<=k;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
maxx[i][j]=max(maxx[i][j-1],maxx[i+(1<<(j-1))][j-1]);
while(m--)
{
int x,y;
read(x);read(y);
int ans = calc(x,y);
printf("%d\n",ans);
}
return 0;
}
没做。
[USACO07JAN] Balanced Lineup G
- 线段树
- 树状数组
主要解决 单点修改,区间查询 和 区间修改,单点查询 的问题(其实其他主要是因为我不会)
// 单点修改,区间查询
#include<bits/stdc++.h>
using namespace std;
int lowbit(int x)
{
return x & -x;
}
const int Maxn = 5e5 + 7;
int n,m;
int tree[Maxn],a[Maxn],c[Maxn];
void updata(int x,int k)
{
while(x<=n)
{
c[x]=c[x] + k;
x = x + lowbit(x);
}
}
int getsum(int x)
{
int ans = 0;
while(x>=1)
{
ans+=c[x];
x=x-lowbit(x);
}
return ans;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
updata(i,a[i]);
}
for(int i=1;i<=m;i++)
{
int op,x,y;
cin>>op>>x>>y;
if(op==1) updata(x,y);
else
cout<<getsum(y)-getsum(x-1)<<endl;
}
return 0;
}
// 区间修改,单点查询
#include<bits/stdc++.h>
using namespace std;
int lowbit(int x)
{
return x & -x;
}
const int Maxn = 5e5 + 7;
int n,m;
int a[Maxn],c[Maxn];
void updata(int x,int k)
{
while(x<=n)
{
c[x]=c[x] + k;
x = x + lowbit(x);
}
}
int getsum(int x)
{
int ans = 0;
while(x>=1)
{
ans+=c[x];
x=x-lowbit(x);
}
return ans;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
updata(i,a[i]-a[i-1]);
}
for(int i=1;i<=m;i++)
{
int op,x,y,k;
cin>>op;
if(op==1)
{
cin>>x>>y>>k;
updata(x,k);
updata(y+1,-k);
}
else
{
cin>>x;
cout<<getsum(x)<<endl;
}
}
return 0;
}
其实对于 区间修改,单点查询 ,还是有点东西的。
首先考虑差分数组:
比如 \(A= \{a_1,a_2,a_3,a_4,a_5 \}\) .
则有 \(B= \{ a_1,a_2-a_1,a_3-a_2,a_4-a_3,a_5-a_4 \}\) .
那么对于区间加,只需要头加,尾减.查询时再做一个前缀和,就是当前的值。
可能线段树的区别就是难以解决 区间修改,区间查询 问题吧(当然,也可能是我不会呢)
数学
高中数学
你看我会嘛 QAQ
初等数论
- 同余式
若两数 \(a,b\) 除以 \(c\) 的余数相等,则称 \(a,b\) 模 \(c\) 同余,记做 $ a \equiv b (mod c)$ .
- 欧几里得算法
求出 \((a,b)\) ,求出 \(a,b\) 两个数的最大公因数。
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
// 坑点:这里不能写成 b % a
- 扩展欧几里得算法
void exgcd(int a,int b,int &x,int &y)
{
if(b==0) {x=1;y=0;return;}
exgcd(b,a%b,y,x);
y-=a/b*x;
}
因为细节比较多,我不一定会(捂脸
- 裴蜀定理
\(\forall a,b,\exists x,y,s.t.ax+by=(a,b)\)
组合数学
待更。
线性代数
其实主要是 矩阵 。
对于 矩阵 的 转置运算 ,这里举例说明:
- 矩阵加速递推