6.26集训--集训模拟赛1

总结

集训第一次NOIP模拟考试,有得也有失

第一题是之前做过的原题,这次没有写出来,交了一个爆搜,不应该
第二题全场只有lsx大佬过了,考试的原数据能贪心过掉80分运气还不错
第三题是题库的原题,但是之前没有做,打表得到了50分
第四题比较水,用线段树维护一个区间最大值就可以

A、信息传递


分析

题目实际上就是让你求有向图中的最小环,这样的算法就很多了

60分爆搜(考场代码)

把每一个点都枚举一遍
还有更优的爆搜可以过掉这道题

#include<bits/stdc++.h>
using namespace std;
const int maxn=200005;
struct asd{
    int from,to,next;
}b[maxn];
int head[maxn];
int tot=1;
void ad(int aa,int bb){
    b[tot].from=aa;
    b[tot].to=bb;
    b[tot].next=head[aa];
    head[aa]=tot++;
}
int n,now,xz;
int vis[maxn];
void dfs(int xx,int cnt){
    if(now) return;
    for(int i=head[xx];i!=-1;i=b[i].next){
        int u=b[i].to;
        if(!vis[u]){
            if(u==xz){
                now=cnt+1;
                return;
            }
            vis[u]=1;
            dfs(u,++cnt);
        }
    }
}
int main(){
    memset(head,-1,sizeof(head));
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int aa;
        scanf("%d",&aa);
        ad(i,aa);
    }
    int ans=0x3f3f3f3f;
    for(int i=1;i<=n;i++){
        memset(vis,0,sizeof(vis));
        xz=i;
        now=0;
        dfs(i,0);
        if(now==0) continue;
        ans=min(ans,now);
    }
    printf("%d
",ans);
    return 0;
}

Tarjan求强连通分量缩点

因为每一个点的出度只能为一,所以有向图中不会出现环套环的情况
因此强连通分量只能是一个环
我们只要找出大小最小的那一个强连通分量就可以了

#include<bits/stdc++.h>
using namespace std;
const int maxn=200005;
struct asd{
    int from,to,next;
}b[maxn];
int head[maxn],tot=1;
void ad(int aa,int bb){
    b[tot].from=aa;
    b[tot].to=bb;
    b[tot].next=head[aa];
    head[aa]=tot++;
}
int shuyu[maxn],siz[maxn];
int dfn[maxn],low[maxn],dfnc,sta[maxn],top,js;
void tar(int xx){
    dfn[xx]=low[xx]=++dfnc;
    sta[++top]=xx;
    for(int i=head[xx];i!=-1;i=b[i].next){
        int u=b[i].to;
        if(!dfn[u]){
            tar(u);
            low[xx]=min(low[xx],low[u]);
        } else if(!shuyu[u]){
            low[xx]=min(low[xx],dfn[u]);
        }
    }
    if(dfn[xx]==low[xx]){ 
        js++;
        while(1){
            int now=sta[top--];
            shuyu[now]=js;
            siz[js]++;
            if(xx==now) break;
        }
    }
}
int main(){
    memset(head,-1,sizeof(head));
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int aa;
        scanf("%d",&aa);
        ad(i,aa);
    }
    for(int i=1;i<=n;i++){
        if(!dfn[i]) tar(i);
    }
    int mmin=0x3f3f3f3f;
    for(int i=1;i<=js;i++){
        if(siz[i]==1) continue;
        mmin=min(mmin,siz[i]);
    }
    printf("%d
",mmin);
    return 0;
}

加权并查集求最小环

如果A可以将信息传递给B,那么将A和B并在一起,更新A和B到祖先节点的距离
如果有两个点祖先节点相同,那么就可以构成一个环,长度为两个点到祖先节点长度之和+1

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;
const int maxn=200010;
int fa[maxn],du[maxn];
int ans;
int zhao(int x){
	if(x==fa[x]) return fa[x];
	int last=fa[x];
	fa[x]=zhao(fa[x]);
	du[x]+=du[last];
	return fa[x];
}
void bing(int x,int y){
	if(zhao(x)==zhao(y)){
		ans=min(ans,du[x]+du[y]+1);
	} else {
		fa[zhao(x)]=zhao(y);
		du[x]=du[y]+1;
	}
}
int main(){
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		fa[i]=i;
	}
	ans=0x3f3f3f3f;
	for(int i=1;i<=n;i++){
		int xx;
		scanf("%d",&xx);
		bing(i,xx);
	}
	printf("%d
",ans);
	return 0;
}

B. 传染病控制


分析

考试时一直以为是一道考察思维量的题目,在想比较优秀的代码
树形DP or 贪心
看了题解后,发现是一个暴力枚举,而且也不太好写

80分贪心(考试代码)

当时写贪心的时候没有想到能水这么多分
思路肯定是不正确的,但是能水过大多数情况

#include<bits/stdc++.h>
using namespace std;
const int maxn=10005;
struct asd{
    int from,to,next;
}b[maxn];
int head[maxn];
int tot=1;
void ad(int aa,int bb){
    b[tot].from=aa;
    b[tot].to=bb;
    b[tot].next=head[aa];
    head[aa]=tot++;
}
int n,p;
int f[maxn];
int dep[maxn],siz[maxn],sizz[maxn],maxd;
void dfs(int now,int fa){
    dep[now]=dep[fa]+1;
    siz[now]=1;
    f[now]=fa;
    for(int i=head[now];i!=-1;i=b[i].next){
        int u=b[i].to;
        if(u==fa) continue;
        sizz[now]++;
        dfs(u,now);
        siz[now]+=siz[u];
    }
}
bool vis[maxn];
void dfs2(int now,int fa){
    vis[now]=1;
    for(int i=head[now];i!=-1;i=b[i].next){
        int u=b[i].to;
        if(u==fa) continue;
        dfs2(u,now);
    }
}
vector<int> g[maxn];
int du;
int main(){
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&p);
    for(int i=1;i<=p;i++){
        int aa,bb;
        scanf("%d%d",&aa,&bb);
        ad(aa,bb);
        ad(bb,aa);
        if(aa==1 || bb==1) du++;
    }
    if(du==1 || du==n-1){
        printf("%d
",du);
        return 0;
    }
    dfs(1,0);
    int ans=0;
    for(int i=1;i<=n;i++){
        maxd=max(dep[i],maxd);
    }
    for(int i=2;i<=maxd;i++){
        int ll=-1,jl=0;
        for(int j=2;j<=n;j++){
            if(vis[j]) continue;
            if(dep[j]==i){
                if(sizz[j]>ll || (sizz[j]>=ll && siz[j]>siz[jl])){
                    ll=sizz[j];
                    jl=j;
                }
            }
        }
        if(jl==0) continue;
        ans+=siz[jl];
        dfs2(jl,f[jl]);
    }
    printf("%d
",n-ans);
    return 0;
}

100分爆搜代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
struct asd{
    int from,to,next;
}b[maxn];
int head[maxn];
int tot=1;
void ad(int aa,int bb){
    b[tot].from=aa;
    b[tot].to=bb;
    b[tot].next=head[aa];
    head[aa]=tot++;
}
int n,p;
int f[maxn];
int dep[maxn],maxd;
void dfs(int now,int fa){
    for(int i=head[now];i!=-1;i=b[i].next){
        int u=b[i].to;
        if(u==fa) continue;
        dep[u]=dep[now]+1;
        f[u]=now;
        maxd=max(maxd,dep[u]);
        dfs(u,now);
    }
}//预处理出每一个节点的深度和它的父亲
int cut[maxn];
void dfs2(int now,int col){
    cut[now]=col;
    for(int i=head[now];i!=-1;i=b[i].next){
        int u=b[i].to;
        if(u==f[now]) continue;
        cut[u]=col;
        dfs2(u,col);
    }
}//把整个子树数染色,标记成已经安全隔离
int cnt[maxn],dep2[maxn][maxn];
int js(int now){
    int sum=0;
    for(int i=1;i<=cnt[now];i++){
        if(cut[dep2[now][i]]==0){
            sum++;
        }
    }
    return sum;
}//统计每一个深度中未被安全隔离的人数
int ans=0x3f3f3f3f;
void solve(int now,int sum){
    if(sum>=ans) return;//剪枝优化
    if(now>maxd || js(now)==0){
        ans=min(ans,sum);
        return;
    }//到达边界
    for(int i=1;i<=cnt[now];i++){
        int to=dep2[now][i];//枚举当前深度所有节点
        if(cut[to]==1) continue;//如果当前节点已被隔离,就不用再遍历
        dfs2(to,1);//否则标记已经安全隔离
        solve(now+1,sum+js(now));//计算答案
        dfs2(to,0);//还原,枚举另一种情况
    }
}
int main(){
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&p);
    for(int i=1;i<=p;i++){
        int aa,bb;
        scanf("%d%d",&aa,&bb);
        ad(aa,bb);
        ad(bb,aa);
    }
    dfs(1,0);
    for(int i=1;i<=n;i++){
        dep2[dep[i]][++cnt[dep[i]]]=i;
    }
    solve(1,1);
    printf("%d
",ans);
    return 0;
}

C、排列



50分打表(考场代码)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=4e6+5;
ll ans;
map<ll,ll> mp;
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        mp.clear();
        ans=0;
        char s[50];
        ll xx;
        scanf("%s",s);
        scanf("%lld",&xx);
        int len=strlen(s);
        if(len==1){
            ll now=s[0]-'0';
            if(now%xx==0) printf("1
");
            else printf("0
");
        } else if(len==2){
            for(int i=0;i<=1;i++){
                for(int j=0;j<=1;j++){
                    if(j==i) continue;
                    ll now=(s[i]-'0')*10ll+(s[j]-'0');
                    if(mp[now]==1) continue;
                    mp[now]=1;
                    if(now%xx==0) ans++;
                }
            }
            printf("%lld
",ans);
        } else if(len==3){
            for(int i=0;i<len;i++){
                for(int j=0;j<len;j++){
                    if(j==i) continue;
                    for(int k=0;k<len;k++){
                        if(k==j || k==i) continue;
                        ll now=(s[i]-'0')*100ll+(s[j]-'0')*10ll+(s[k]-'0');
                        if(mp[now]==1) continue;
                        mp[now]=1;
                        if(now%xx==0) {
                            ans++;
                        }
                    }
                }
            }
            printf("%lld
",ans);
        } else if(len==4){
            for(int i1=0;i1<len;i1++){
                for(int i2=0;i2<len;i2++){
                    if(i1==i2) continue;
                    for(int i3=0;i3<len;i3++){
                        if(i3==i1 || i3==i2) continue;
                        for(int i4=0;i4<len;i4++){
                            if(i4==i1 || i4==i2 || i4==i3) continue;
                            ll now=(s[i1]-'0')*1000ll+(s[i2]-'0')*100ll+(s[i3]-'0')*10ll+(s[i4]-'0');
                            if(mp[now]==1) continue;
                            mp[now]=1;
                            if(now%xx==0){
                                ans++;
                            }
                        }
                    }
                }
            }
            printf("%lld
",ans);
        } else if(len==5){
            for(int i1=0;i1<len;i1++){
                for(int i2=0;i2<len;i2++){
                    if(i1==i2) continue;
                    for(int i3=0;i3<len;i3++){
                        if(i3==i1 || i3==i2) continue;
                        for(int i4=0;i4<len;i4++){
                            if(i4==i1 || i4==i2 || i4==i3) continue;
                            for(int i5=0;i5<len;i5++){
                                if(i5==i1 || i5==i2 || i5==i3 || i5==i4) continue;
                                ll now=(s[i1]-'0')*10000ll+(s[i2]-'0')*1000ll+(s[i3]-'0')*100ll+(s[i4]-'0')*10ll+(s[i5]-'0');
                                if(mp[now]==1) continue;
                                mp[now]=1;
                                if(now%xx==0){
                                    ans++;
                                }
                            }
                        }
                    }
                }
            }
            printf("%lld
",ans);
        } else if(len==6){
            for(int i1=0;i1<len;i1++){
                for(int i2=0;i2<len;i2++){
                    if(i1==i2) continue;
                    for(int i3=0;i3<len;i3++){
                        if(i3==i1 || i3==i2) continue;
                        for(int i4=0;i4<len;i4++){
                            if(i4==i1 || i4==i2 || i4==i3) continue;
                            for(int i5=0;i5<len;i5++){
                                if(i5==i1 || i5==i2 || i5==i3 || i5==i4) continue;
                                for(int i6=0;i6<len;i6++){
                                    if(i6==i1 || i6==i2 || i6==i3 || i6==i4 || i6==i5) continue;
                                    ll now=(s[i1]-'0')*100000ll+(s[i2]-'0')*10000ll+(s[i3]-'0')*1000ll+(s[i4]-'0')*100ll;
                                    now+=(s[i5]-'0')*10ll+(s[i6]-'0');
                                    if(mp[now]==1) continue;
                                    mp[now]=1;
                                    if(now%xx==0){
                                        ans++;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            printf("%lld
",ans);
        } else if(len==7){
            for(int i1=0;i1<len;i1++){
                for(int i2=0;i2<len;i2++){
                    if(i1==i2) continue;
                    for(int i3=0;i3<len;i3++){
                        if(i3==i1 || i3==i2) continue;
                        for(int i4=0;i4<len;i4++){
                            if(i4==i1 || i4==i2 || i4==i3) continue;
                            for(int i5=0;i5<len;i5++){
                                if(i5==i1 || i5==i2 || i5==i3 || i5==i4) continue;
                                for(int i6=0;i6<len;i6++){
                                    if(i6==i1 || i6==i2 || i6==i3 || i6==i4 || i6==i5) continue;
                                    for(int i7=0;i7<len;i7++){
                                        if(i7==i1 || i7==i2 || i7==i3 || i7==i4 || i7==i5 || i7==i6) continue;
                                        ll now=(s[i1]-'0')*1000000ll+(s[i2]-'0')*100000ll+(s[i3]-'0')*10000ll+(s[i4]-'0')*1000ll;
                                        now+=(s[i5]-'0')*100ll+(s[i6]-'0')*10ll+(s[i7]-'0');
                                        if(mp[now]==1) continue;
                                        mp[now]=1;
                                        if(now%xx==0){
                                            ans++;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            printf("%lld
",ans);
        } else if(len==8){
            for(int i1=0;i1<len;i1++){
                for(int i2=0;i2<len;i2++){
                    if(i1==i2) continue;
                    for(int i3=0;i3<len;i3++){
                        if(i3==i1 || i3==i2) continue;
                        for(int i4=0;i4<len;i4++){
                            if(i4==i1 || i4==i2 || i4==i3) continue;
                            for(int i5=0;i5<len;i5++){
                                if(i5==i1 || i5==i2 || i5==i3 || i5==i4) continue;
                                for(int i6=0;i6<len;i6++){
                                    if(i6==i1 || i6==i2 || i6==i3 || i6==i4 || i6==i5) continue;
                                    for(int i7=0;i7<len;i7++){
                                        if(i7==i1 || i7==i2 || i7==i3 || i7==i4 || i7==i5 || i7==i6) continue;
                                        for(int i8=0;i8<len;i8++){
                                        if(i8==i1 || i8==i2 || i8==i3 || i8==i4 || i8==i5 || i8==i6 || i8==i7) continue;
                                            ll now=(s[i1]-'0')*10000000ll+(s[i2]-'0')*1000000ll+(s[i3]-'0')*100000ll+(s[i4]-'0')*10000ll;
                                        now+=(s[i5]-'0')*1000ll+(s[i6]-'0')*100ll+(s[i7]-'0')*10ll+(s[i8]-'0');
                                        if(mp[now]==1) continue;
                                        mp[now]=1;
                                        if(now%xx==0){
                                            ans++;
                                        }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            printf("%lld
",ans);
        }  else if(len==9){
            for(int i1=0;i1<len;i1++){
                for(int i2=0;i2<len;i2++){
                    if(i1==i2) continue;
                    for(int i3=0;i3<len;i3++){
                        if(i3==i1 || i3==i2) continue;
                        for(int i4=0;i4<len;i4++){
                            if(i4==i1 || i4==i2 || i4==i3) continue;
                            for(int i5=0;i5<len;i5++){
                                if(i5==i1 || i5==i2 || i5==i3 || i5==i4) continue;
                                for(int i6=0;i6<len;i6++){
                                    if(i6==i1 || i6==i2 || i6==i3 || i6==i4 || i6==i5) continue;
                                    for(int i7=0;i7<len;i7++){
                                        if(i7==i1 || i7==i2 || i7==i3 || i7==i4 || i7==i5 || i7==i6) continue;
                                        for(int i8=0;i8<len;i8++){
                                        if(i8==i1 || i8==i2 || i8==i3 || i8==i4 || i8==i5 || i8==i6 || i8==i7) continue;
                                            for(int i9=0;i9<len;i9++){
                                            if(i9==i1 || i9==i2 || i9==i3 || i9==i4 || i9==i5 || i9==i6 || i9==i7 || i9==i8) continue;
                                                ll now=(s[i1]-'0')*100000000ll+(s[i2]-'0')*10000000ll+(s[i3]-'0')*1000000ll+(s[i4]-'0')*100000ll;
                                        now+=(s[i5]-'0')*10000ll+(s[i6]-'0')*1000ll+(s[i7]-'0')*100ll+(s[i8]-'0')*10ll+(s[i9]-'0');
                                        if(mp[now]==1) continue;
                                        mp[now]=1;
                                        if(now%xx==0){
                                            ans++;
                                        }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            printf("%lld
",ans);
        } else {
            for(int i1=0;i1<len;i1++){
                for(int i2=0;i2<len;i2++){
                    if(i1==i2) continue;
                    for(int i3=0;i3<len;i3++){
                        if(i3==i1 || i3==i2) continue;
                        for(int i4=0;i4<len;i4++){
                            if(i4==i1 || i4==i2 || i4==i3) continue;
                            for(int i5=0;i5<len;i5++){
                                if(i5==i1 || i5==i2 || i5==i3 || i5==i4) continue;
                                for(int i6=0;i6<len;i6++){
                                    if(i6==i1 || i6==i2 || i6==i3 || i6==i4 || i6==i5) continue;
                                    for(int i7=0;i7<len;i7++){
                                        if(i7==i1 || i7==i2 || i7==i3 || i7==i4 || i7==i5 || i7==i6) continue;
                                        for(int i8=0;i8<len;i8++){
                                        if(i8==i1 || i8==i2 || i8==i3 || i8==i4 || i8==i5 || i8==i6 || i8==i7) continue;
                                            for(int i9=0;i9<len;i9++){
                                            if(i9==i1 || i9==i2 || i9==i3 || i9==i4 || i9==i5 || i9==i6 || i9==i7 || i9==i8) continue;
                                                for(int i10=0;i10<len;i10++){
                                                if(i10==i1 || i10==i2 || i10==i3 || i10==i4 || i10==i5 || i10==i6 || i10==i7) continue;
                                                 if( i10==i8 || i10==i9) continue;
                                                    ll now=(s[i1]-'0')*1000000000ll+(s[i2]-'0')*100000000ll+(s[i3]-'0')*10000000ll;
                                                    now+=(s[i4]-'0')*1000000ll;
                                                    now+=(s[i5]-'0')*100000ll+(s[i6]-'0')*10000ll+(s[i7]-'0')*1000ll+(s[i8]-'0')*100ll;
                                                    now+=(s[i9]-'0')*10ll+(s[i10]-'0');
                                                    if(mp[now]==1) continue;
                                                    mp[now]=1;
                                                    if(now%xx==0){
                                                    ans++;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            printf("%lld
",ans);
        }
    }
    return 0;
}

100分STL

STL中有一个自动求全排列的函数(next \_ permutation)
所以代码就很简洁了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[15],t;
char s[15];
int main(){
    scanf("%lld",&t);
    while(t--){
        ll now;
        scanf("%s%lld",s,&now);
        ll len=strlen(s);
        for(int i=1;i<=len;i++){
            a[i]=s[i-1]-'0';
        }
        sort(a+1,a+1+len);
        ll ans=0;
        while(1){
            ll tot=0;
            for(int i=1;i<=len;i++){
                tot=tot*10+a[i];
            }
            if(tot%now==0) ans++;
            if(next_permutation(a+1,a+len+1)==0) break;
        }
        printf("%lld
",ans);
    }
    return 0;
}

D、最大数


分析

显然用线段树维护一个区间最值

57分暴力(对拍用)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int cnt=0;
const int maxn=2e5+5;
ll lat;
ll a[maxn];
int main(){
    int m;
    ll d;
    scanf("%d%lld",&m,&d);
    for(int i=1;i<=m;i++){
        char ch;
        ll now;
        scanf(" %c %lld",&ch,&now);
        if(ch=='A'){
            a[++cnt]=(lat+now)%d;
        } else {
            ll mmax=0;
            for(int j=cnt;j>cnt-now;j--){
                mmax=max(mmax,a[j]);
            }
            lat=mmax;
            printf("%lld
",mmax);
        }
    }
}

100分代码(线段树)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+5;
struct trr{
    ll l,r,w;
}tr[maxn];
ll m,mod,las;
void push_up(ll da){
    tr[da].w=max(tr[da<<1].w,tr[da<<1|1].w);
}
void build(ll da,ll s,ll t){
    tr[da].l=s;
    tr[da].r=t;
    if(s==t){
        tr[da].w=0;
        return;
    }
    int mids=(s+t)>>1;
    build(da<<1,s,mids);
    build(da<<1|1,mids+1,t);
    push_up(da);
}
void xg(ll da,ll gg,ll ww){
    if(tr[da].l==tr[da].r){
        tr[da].w=ww;
        return;
    }
    ll mids=(tr[da].l+tr[da].r)>>1;
    if(gg<=mids) xg(da<<1,gg,ww);
    else xg(da<<1|1,gg,ww);
    push_up(da);
}
ll cx(ll da,ll s,ll t){
    if(tr[da].l>=s && tr[da].r<=t){
        return tr[da].w%mod;
    }
    ll ans=0;
    ll mids=(tr[da].l+tr[da].r)>>1;
    if(s<=mids) ans=max(ans,cx(da<<1,s,t));
    if(t>mids) ans=max(ans,cx(da<<1|1,s,t));
    return ans%mod;
}
ll cnt=0;
int main(){
    scanf("%lld%lld",&m,&mod);
    build(1,1,m);
    for(ll i=1;i<=m;i++){
        char ch;
        ll now;
        scanf(" %c %lld",&ch,&now);
        if(ch=='A'){
            xg(1,++cnt,(now+las)%mod);
        } else {
            las=cx(1,cnt-now+1,cnt);
            printf("%lld
",las);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/liuchanglc/p/13195528.html