目录
湖二师HUE寒假集训
本人有幸参与由宋学长举办的寒假集训,难度感觉算是算法入门颇深,题目还是精心挑选过的,记录下来留个纪念
https://www.luogu.com.cn/team/53776
里面的入门算法模板在我眼里是最重要的(dp当然也非常重要,不过除了新手真正学计算机算法的大部分人应该都会,,,)
P1177 【模板】快速排序
P1177 【模板】快速排序 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
快排在我记忆中过于久远,经典二分法,STLsort法等等...
二分法
#include<stdio.h>
int a[100001];
void zzsort(int min,int max)
{
int mid=a[(min+max)/2];
int n1=min;
int n2=max;
do
{
while (a[n1]>mid)n1++;
while (a[n2]<mid)n2--;
if (n1<=n2)
{
a[0]=a[n1];
a[n1]=a[n2];
a[n2]=a[0];
n1++;
n2--;
}
} while (n1<=n2);
if (min<n2)zzsort(min,n2);
if (n1<max)zzsort(n1,max);
}
int main()
{
int n;
scanf("%d",&n);
int i,k,l;
for ( i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
}
zzsort(1,n);
for ( i = n; i >=1; i--)printf("%d ",a[i]);
}
sort法(题目明令最好不用使用)
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int a[100001],n;
int main()
{
cin>>n;
for (int i = 0; i < n; i++)cin>>a[i];
sort(a,a+n);
for (int i = 0; i < n; i++)cout<<a[i]<<" ";
}
感觉清晰明了好多,虽然题目有些要求没有实现
P3367 【模板】并查集
P3367 【模板】并查集 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
找父亲的代码比较重要,,,
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#define PI 3.1415
#define ll long long
using namespace std;
int n,m,a[10005];
int fd(int x)
{
if (a[x]!=x)
{
a[x]=fd(a[x]);
}
return a[x];
}
int main()
{
cin>>n>>m;
for (int i = 0; i <=n; i++)a[i]=i;
while (m--)
{
int j,x,y;
cin>>j>>x>>y;
if (j==2)
{
if (fd(x)==fd(y))
{
cout<<"Y\n";
}else
{
cout<<"N\n";
}
}else
{
a[fd(x)]=fd(y);
}
}
}
P3383 【模板】线性筛素数
P3383 【模板】线性筛素数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
欧拉筛。
#include<cstdio>
#include<iostream>
#include<algorithm>
#define PI 3.1415
#define ll long long
#define mod 1000000007
using namespace std;
int n,m,a[100000001],k,b[100000005],ns;
void zzs()
{
for (int i = 2; i <=n; i++)
{
if (a[i]==0)b[++ns]=i;
for (int j = 1; j<=ns&&i*b[j]<=n; j++)
{
a[i*b[j]]=1;
if (i%b[j]==0)break;
}
}
}
int main()
{
cin>>n>>m;
zzs();
while (m--)
{
cin>>k;
printf("%d\n",b[k]);
}
}
P1226 【模板】快速幂||取余运算
P1226 【模板】快速幂||取余运算 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include<cstdio>
#include<iostream>
#include<algorithm>
#define PI 3.1415
#define ll long long
#define mod 1000000007
using namespace std;
ll a,b,p,aa,bb;
int main()
{
cin>>a>>b>>p;
aa=a;
bb=b;
ll sum=1;
a%=p;
while (b)
{
if (b&1)
{
sum=sum*a%p;
}
a=(a*a)%p;
b>>=1;
}
printf("%lld^%lld mod %lld=%lld",aa,bb,p,sum%p);
}
P3378 【模板】堆
P3378 【模板】堆 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
一开始还想搞点骚操作,定义俩个坐标n1.n2,n1在最左,n2在最右,删数就n1++,加数就n2++,利用二分法减时间复杂度,只能说难等大雅之堂
普遍操作:手打堆,STL大法
差别:手打堆代码实现快一点点,STL实现代码快亿点点
手打堆:
#include<cstdio>
#include<iostream>
#include<algorithm>
#define PI 3.1415
#define ll long long
#define mod 1000000007
using namespace std;
ll n,op,m,cnt,hd[1000005];
void add(ll x)
{
hd[++cnt]=x;
int nw=cnt,nt;
while (nw>1)
{
nt=nw/2;
if(hd[nw]>=hd[nt])return;
swap(hd[nw],hd[nt]);
nw=nt;
}
}
void clr()
{
swap(hd[cnt],hd[1]);
cnt--;
int nw=1,nt;
while (nw*2<=cnt)
{
nt=nw*2;
if(nt+1<=cnt&&hd[nt]>hd[nt+1])nt++;
if(hd[nt]<hd[nw])swap(hd[nw],hd[nt]);
else return;
nw=nt;
}
}
int main()
{
cin>>n;
while (n--)
{
cin>>op;
if (op==1)
{
cin>>m;
add(m);
}else if (op==2)
{
cout<<hd[1]<<endl;
}else if (op==3)
{
clr();
}
}
}
STL(一开始我也不清楚,不过不会就学吗,会了谁还用手打???)
当然用了虚函数一些知识,例如重载运算符,实在无法忍受的可以自行去先了解一下:
#include<cstdio>
#include<iostream>
#include<algorithm>
//#include<vector>
//#include<stack>
//#include<set>
//#include<bitset>
//#include<map>
//#include<unordered_map> //哈希,O(1),map O(log n)
#include<queue>
//#include <cstring>
//#include <cmath>
/*inline int read()
{
int f=1,x=0; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=getchar();
return f*x;
}*/
#define PI 3.1415
#define ll long long
#define mod 1000000007
using namespace std;
priority_queue<int,vector<int>,greater<int> > q;
int n,op,m;
int main()
{
cin>>n;
while (n--)
{
cin>>op;
if (op==1)
{
cin>>m;
q.push(m);
}else if (op==2)
{
cout<<q.top()<<endl;
}else if (op==3)
{
q.pop();
}
}
}
下面介绍(借鉴)一下priority_queue :
及 std::greater:
最后展示一下差别:
手打:
STL:
测试点9还偏向STL,也许这就是c++的魅力
P5788 【模板】单调栈
P5788 【模板】单调栈 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
唯一坑点,用cin,cout在这个题上会使时间翻倍。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<stack>
#define PI 3.1415
#define ll long long
#define mod 1000000007
using namespace std;
int n,a[3000006],f[3000006];
stack<int>st;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=n;i>0;i--){
while (!st.empty()&&a[i]>=a[st.top()])st.pop();
f[i]=st.empty()?0:st.top();
st.push(i);
}
for(int i=1;i<=n;i++)printf("%d ",f[i]);
}
P1886 滑动窗口 /【模板】单调队列
P1886 滑动窗口 /【模板】单调队列 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
把每个区段都维护成一个队列(抽象理解)
#include<cstdio>
#include<iostream>
#include<algorithm>
#define PI 3.1415
#define ll long long
#define mod 1000000007
using namespace std;
int n,m;
int q1[1000001],q2[1000001];
int a[1000001];
int mi()
{
int h=1,t=0;
for(int i=1;i<=n;i++)
{
while(h<=t&&q1[h]+m<=i) h++;
while(h<=t&&a[i]<a[q1[t]]) t--;
q1[++t]=i;
if(i>=m) printf("%d ",a[q1[h]]);
}
cout<<endl;
}
int mx()
{
int h=1,t=0;
for(int i=1;i<=n;i++)
{
while(h<=t&&q2[h]+m<=i) h++;
while(h<=t&&a[i]>a[q2[t]]) t--;
q2[++t]=i;
if(i>=m) printf("%d ",a[q2[h]]);
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
mi();
mx();
return 0;
}
P3375 【模板】KMP字符串匹配
P3375 【模板】KMP字符串匹配 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
kmp这个网上的讲解都比较全面,至少比我好,自己多脑补几个例子即可理解
include<cstdio>
#include<iostream>
#include<algorithm>
#define PI 3.1415
#define ll long long
#define mod 1000000007
using namespace std;
string st1,st2;
int l1,l2,k[10000005];
int main()
{
cin>>st1>>st2;
l1=st1.length();
l2=st2.length();
st1=" "+st1;
st2=" "+st2;
int j=0;
for (int i = 2; i <=l2; i++)
{
while(j&&st2[i]!=st2[j+1])j=k[j];
if(st2[i]==st2[j+1])j++;
k[i]=j;
}
j=0;
for (int i = 1; i <=l1; i++)
{
while(j&&st1[i]!=st2[j+1])j=k[j];
if (st1[i]==st2[j+1])j++;
if(j==l2){
cout<<i-l2+1<<endl;
j=k[j];
}
}
for (int i = 1; i <=l2; i++)
{
cout<<k[i]<<" ";
}
}
P3370 【模板】字符串哈希
P3370 【模板】字符串哈希 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
这个题好多种思路,比如哈希表什么之类的,意思就是把字符串转化为数字,
当然还是STL大法好
#include<iostream>
#include<map>
using namespace std;
map<string,int>mp;
int sum,n;
char a[1505];
int main()
{
scanf("%d",&n);
while (n--)
{
scanf("%s",a);
mp[a]++;
}
printf("%d",mp.size());
}
P3371 【模板】单源最短路径(弱化版)
P3371 【模板】单源最短路径(弱化版) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
一开始用我最喜欢的SPFA算法过关
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#define PI 3.1415
#define ll long long
#define mod 1000000007
using namespace std;
int n,m,s,nn[10005],lmi[10005],j[10005],tot;
queue<int>qe;
struct node
{
int nt,to,l;
}nd[500005];
void add(int x,int y,int l)
{
nd[++tot].nt=nn[x];
nd[tot].to=y;
nd[tot].l=l;
nn[x]=tot;
}
int main()
{
cin>>n>>m>>s;
for (int i = 1; i <=n; i++)lmi[i]=1234567890;
while (m--)
{
int l,x,y;
cin>>x>>y>>l;
if (x==y)continue;
add(x,y,l);
}
qe.push(s);
lmi[s]=0;
j[s]=1;
while (!qe.empty())
{
int w=qe.front();
j[w]=0;
qe.pop();
for (int i = nn[w]; i; i=nd[i].nt)
{
int ww=nd[i].to;
if (lmi[ww]>lmi[w]+nd[i].l)
{
lmi[ww]=lmi[w]+nd[i].l;
if (!j[ww])
{
j[ww]=1;
qe.push(ww);
}
}
}
}
for (int i = 1; i <=n; i++){
if (lmi[i]==1234567890)
{
printf("2147483647 ");
continue;
}
printf("%d ",lmi[i]);
}
}
但毕竟是个弱化版,于是接着挑战标准版
P4779 【模板】单源最短路径(标准版)
P4779 【模板】单源最短路径(标准版) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
果然TLE了,含泪又去学dijkstra算法
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
//#include<stack>
//#include<set>
//#include<bitset>
//#include<map>
//#include<unordered_map> //哈希,O(1),map O(log n)
#include<queue>
//#include <cstring>
//#include <cmath>
/*inline int read()
{
int f=1,x=0; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=getchar();
return f*x;
}*/
#define PI 3.1415
#define ll long long
#define mod 1000000007
using namespace std;
int n,m,s,nn[100005],len[100005],j[100005],tot;
struct pri
{
int l;
int st;
bool operator <(const pri &pri2)const
{
return pri2.l<l;
}
};
priority_queue<pri>qe;
struct node
{
int nt,to,l;
}nd[500005];
void add(int x,int y,int l)
{
nd[++tot].nt=nn[x];
nd[tot].to=y;
nd[tot].l=l;
nn[x]=tot;
}
int main()
{
cin>>n>>m>>s;
for (int i = 1; i <=n; i++)len[i]=1e10;
int mm=m;
while (mm--)
{
int l,x,y;
cin>>x>>y>>l;
if (x==y)continue;
add(x,y,l);
}
len[s]=0;
qe.push((pri){0,s});
while (!qe.empty())
{
pri p=qe.top();
qe.pop();
int w=p.st;
if (!j[w])
{
j[w]=1;
for (int i = nn[w]; i ; i=nd[i].nt)
{
int ww=nd[i].to;
len[ww]=min(len[ww],len[w]+nd[i].l);
if(!j[ww])qe.push((pri){len[ww],ww});
}
}
}
for (int i = 1; i <=n; i++){
printf("%d ",len[i]);
}
}
其实我也一知半解。。
P3366 【模板】最小生成树
P3366 【模板】最小生成树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
新手总要去看解析的,了解到俩种做法,Prim,Kruskal
区别:Prim在稠密图中比Kruskal优,在稀疏图中比Kruskal劣
Kruskal:
void solve(){
struct node{
int u,v,l;
bool operator < (const Point &node2) const{return this.l<node2.l;}
}e[400005];
int fd(int x){if(f[x]==x)return x;return f[x]=fd(f[x]);}
int n,m,u,v,l,f[N],cnt,vis[N];
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>u>>v>>l,e[i]={u,v,l};
sort(e+1,e+1+m);
for(int i=1;i<=m;i++){
int fu=fd(e[i].u),fv=fd(e[i].v),l=e[i].l;
if(!vis[fu]&&!vis[fv])vis[fu]=vis[fv]=1,cnt+=2,ans+=l;
if(!vis[fu])vis[fu]=1,cnt++,ans+=l;
if(!vis[fv])vis[fv]=1,cnt++,ans+=l;
if(cnt==n)return ans;
}
}
Prim:
void solve(){
vector<pair<int,int>>e[N]
int n,m,u,v,l,dis[N],vis[N],ans;
cin>>n>>m;memset(dis,0x7f,sizeof(dis));
for(int i=1;i<=n;i++)cin>>u>>v>>l,e[u].push_pack({v,l}),e[v].push_pack({u,l});
int u=1,cnt;
while(++cnt<=n){
if(vis[u])return False;
vis[u]=1;int mi=MAX;
for(auto it:e[u]){
if(vis[it.first])continue;
dis[it.first]=min(dis[it.first],dis[u]+it.second);
}
for(int i=1;i<=n;i++){
if(vis[i])continue;
if(dis[i]<mi){mi=dis[i],u=i;}
}
ans+=mi;
}
}
还有三个题涉及强大的数学知识,近期不打算处理