湖二师HUE寒假集训

目录

          

湖二师HUE寒假集训

P1177 【模板】快速排序

P3367 【模板】并查集

P3383 【模板】线性筛素数

P1226 【模板】快速幂||取余运算

P3378 【模板】堆

P5788 【模板】单调栈

P1886 滑动窗口 /【模板】单调队列 

P3375 【模板】KMP字符串匹配 

P3370 【模板】字符串哈希

P3371 【模板】单源最短路径(弱化版)

P4779 【模板】单源最短路径(标准版)

P3366 【模板】最小生成树


          

 湖二师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;
    }
}

还有三个题涉及强大的数学知识,近期不打算处理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zjhhhzj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值