集训经历
暑假集训伴随着最后一场百度之星个人赛的结束而结束,这一个多月的训练让我感受到了为自己目标而奋斗的满足感。
七月二十三号回到学校开始集训,在家里面完了大半个月,不得不说在家里面是真的很摆,一天哪怕是学了一个小时就感觉 哇!今天学的好充实啊^ - ^,所以说还是在学校训练的效果比较好。
到校第二天在机房打了场赛氪的全国大学生算法设计与编程挑战赛(夏季赛),第一次打这个比赛但是和我想象中的不太一样,懂得都懂。本来以为是拿不到奖了,没想到结果出来之后我们队也是银奖,不多说,懂得都懂。证书是挺不错的。
因为疫情原因我会校晚了一周,所以刚来的前两天任务量很大,边学新内容边补我没来的时候讲的内容。
集训每天都是上午九点到十一点一场手速赛,打完之后队长给我们讲一讲题,下午补一下题在温习一下前面学的内容,继续刷题比赛的时候大部分时间都是在罚坐(太菜了
训练的这一个月每天的训练赛加起来大概一百三十题左右,再加上自己刷题,刷刷自己学校OJ的题,打打牛客的比赛,还有几天一场的cf大概集训期间刷了两百五十道左右,训练量还是不小的,只是最后几天大家都累了,训练效率下来了,不然可能会更多。每天都是在刷题比赛训练学习新内容,过程虽然累但是结束了之后回头看却感觉很充实。集训最后百度之星的第二场还现学了主席树求区间前K大数和^ - ^,确实离谱嗷。
集训收获
在集训期间训练和学习了许多内容包括:
离散化处理
//储存所有离散化的值
vector<int>alls;
//排序
sort(alls.begin(),alls.end());
//去掉重复元素
alls.erase(unique(alls.begin(),alls.end()),alls.end());
//二分求出x对应的离散化的值
int find(int x)
{
int l=0,r=alls.size()-1;
while(l<r)
{
int min=l+r>>1;
if(alls[mid]>=x)r=mid;
else l=mid+1;
}
return r+1;
}
KMP
for(int i=2,j=0;i<=len2;i++)
{
while(j&&str[i]!=str[j+1])j=ne[j];
if(str[i]==str[j+1])j++;
ne[i]=j;
}
Tire
void insert(char str[])
{
int p=0;
for(int i=0;str[i];i++)
{
int u=str[i]-'a';
if(!son[p][u])son[p][u]=++idx;
p=son[p][u];
}
cnt[p]++;
}
int query(char str[])
{
int p=0;
for(int i=0;str[i];i++)
{
int u=str[i]-'a';
if(!son[p][u])return 0;
p=son[p][u];
}
return cnt[p];
}
并查集
int find(int x)
{
if(p[x]!=x)p[x]=find(p[x]);
return p[x];
}
二分图匹配
bool find(int x)
{
for(int i=h[x];i!=-1;i=ne[i])
{
int j=e[i];
if(!st[j])
{
st[j]=true;
if(match[j]==0||find(match[j]))
{
match[j]=x;
return true;
}
}
}
return false;
}
树状数组
int lowbit(int x)//c[i]的区间长度
{
return x&-x;
}
void add(int i,int x)//点更新,a[i]加上z
{
for(;i<=n;i+=lowbit(i));//更新所有后继
c[i]+=x;
}
int sum(int i)//求区间和
{
int s=0;
for(;i>0;i-=lowbit(i))//累加所有前驱
s+=c[i];
return s;
}
int sumn(int l,int r)
{
return sum[r]-sum[l-1];
}
拓扑排序
bool topsort()
{
int hh=0,tt=-1;
for(int i=1;i<=n;i++)
if(!d[i])
q[++tt]=i;
while(hh<=tt)
{
int t=q[hh++];
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
d[j]--;
if(d[j]==0)
q[++tt]=j;
}
}
return tt=n-1;
}
二分答案
最大值最小
while(l<r)
{
int mid=l+r>>1;
if(check(mid))r=mid;
else l=mid+1;
}
最小值最大
while(l+1<r)
{
int mid=l+r>>1;
if(check(mid))l=mid;
else r=mid;
}
线段树
struct node{
int l,r,mx;
}tree[N];
void build(int k,int l,int r)
{
tree[k].l=l;
tree[k].r=r;
if(l==r)//找到了叶子节点
{
tree[k].mx=a[l];//树叶就等于a[i]
return;
}
int mid=(l+r)/2;
build(2*k,l,mid);//左子树
build(2*k+1,mid+1,r);//右子树
tree[k].mx=max(tree[k*2].mx,tree[k*2+1].mx);//递归更新线段区间最大值
}
void updata(int k,int i,int v)//点更新
{
if(tree[k].l==tree[k].r&&tree[k].l==i)
{
tree[k].mx=v;
return;
}
int mid=(tree[k].l+tree[k].r)/2;
if(i<=mid)
updata(2*k,i,c);
else
updata(2*k+1,i,v);
tree[k].mx=max(tree[2*k].mx,tree[2*k+1].mx);
}
最后一场个人赛现学的主席树
//theme:给定n个数,q次询问,每次求区间[l,r]中从小到大排序后第k个数。1 <= n <= 100 000, 1 <= q <= 5 000,1 <=l <=r<= n, 1 <= k <= j - i + 1
#include <iostream>
#include<cstdio>
#include<algorithm>
#define midd (l+r)/2
using namespace std;
typedef long long ll;
const int N = 200010;
int n, q, sz, cnt = 0;
int a[N], b[N], T[N];//a为原数组,b为排序离散化数组,T[i]为(值)[1,i]的根节点
int sum[N<<5], L[N<<5], R[N<<5];
inline int build(int l, int r)
{
int rt = ++ cnt;
sum[rt] = 0;
if (l < r){
L[rt] = build(l, midd);
R[rt] = build(midd+1, r);
}
return rt;
}
inline int update(int pre, int l, int r, int x)
{
int rt = ++ cnt;
L[rt] = L[pre]; R[rt] = R[pre]; sum[rt] = sum[pre]+1;
if (l < r){
if (x <= midd) L[rt] = update(L[pre], l, midd, x);
else R[rt] = update(R[pre], midd+1, r, x);
}
return rt;
}
inline int query(int u, int v, int l, int r, int k)//返回下标,即<=k个数
{
if (l >= r) return l;
int x = sum[L[v]] - sum[L[u]];
if (x >= k) return query(L[u], L[v], l, midd, k);
else return query(R[u], R[v], midd+1, r, k-x);
}
int main()
{
while(scanf("%d%d", &n, &q)!=EOF){
cnt=0;
for (int i = 1; i <= n; i ++){
scanf("%d", &a[i]);
b[i] = a[i];
}
sort(b+1, b+1+n);
sz = unique(b+1, b+1+n)-b-1;
T[0] = build(1, sz);
for (int i = 1; i <= n; i ++){
int t = lower_bound(b+1, b+1+sz, a[i])-b;
T[i] = update(T[i-1], 1, sz, t);
}
while (q --){
int l, r, k;
scanf("%d%d%d", &l, &r ,&k);
// k= r-l+1-k+1;//求第k大时改一下就行
int idx=query(T[l-1], T[r], 1, sz, k);
int ans=b[idx];
printf("%d\n",ans);
}
}
return 0;
}
还有DFS、BFS、状压DP、环状DP、多源BFS、多源DFS、双端队列、双向广搜、迭代加深等内容,
经过集训收获了许多的东西。
从一开始见到题目就发愁想不出来怎么写,慢慢的到见到题目之后知道这个题目考察的是什么知识点,感觉慢慢的打开了算法世界的大门,我感觉这是一种心态的转变也是成长。在机房里学长还有队友每天都在努力的训练,这种氛围一直在推动着我们每一个人在算法的道路上继续前进。自己现在的水平自己内心很清楚,我也更清楚的认识到了自己跟强者之间的差距,距离是慢慢拉出来的。还得继续加练,不断变强。通过这次暑假集训,我们也充分意识到了和别人们的差距,也算是开阔了眼界。而且也学到了不少新知识,动态规划,图论,和一些数论的知识,也充分意识到了学好数学是多么重要。竞赛之路还很长,现在只是开始,后面还有数不尽的困难在等着我们,但是我也并不气馁,千里之行始于足下,现在就要开始加把劲了。自信来源于训练!