PAT顶级2021-09题解

Posted nonameeeeee

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PAT顶级2021-09题解相关的知识,希望对你有一定的参考价值。

怎么出的这么水啊…感觉全世界都AK了啊(雾)

(也可能是姥姥错误估计了难度)

T1

题目大意:按照顺序给你一些点,让你插入一个二叉堆里。输出按层次遍历的节点编号(N<=30)

读懂题目就能过了…动态开点写写就没问题了,遍历使用bfs就可。

C++代码实现如下:

#include<bits/stdc++.h>
#define maxn 100005
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;

inline int read()
{
	int x=0,w=1; char c=getchar();
	while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
	while(c<='9'&&c>='0') x=(x<<1)+(x<<3)+c-'0',c=getchar();
	return w==1?x:-x;
}

int n,ls[maxn],rs[maxn],cnt,a[maxn],w[maxn];
struct node{int x,id;}p[maxn];
queue <int> q;
vector <int> v;

inline bool cmp(node a,node b){return a.id<b.id;}

inline void ins(int u,int val,int val2)
{
	if(val>w[u])
	{
		if(!rs[u]) {rs[u]=++cnt; w[cnt]=val; a[cnt]=val2; return;}
		else return ins(rs[u],val,val2);
	}
	else if(val<w[u])
	{
		if(!ls[u]) {ls[u]=++cnt; w[cnt]=val; a[cnt]=val2; return;}
		else return ins(ls[u],val,val2);
	}
}

int main()
{
	n=read(); rep(i,1,n) p[i].x=read(),p[i].id=read(); sort(p+1,p+n+1,cmp);
	a[1]=p[1].id; w[1]=p[1].x; cnt=1; rep(i,2,n) ins(1,p[i].x,p[i].id);
	q.push(1);
	while(!q.empty())
	{
		int u=q.front(); q.pop(); v.pb(u);
		if(ls[u]) q.push(ls[u]);
		if(rs[u]) q.push(rs[u]);
	}
	for(int i=0;i<v.size()-1;i++) printf("%d ",w[v[i]]);
	printf("%d",w[v[v.size()-1]]); puts("");
	for(int i=0;i<v.size()-1;i++) printf("%d ",a[v[i]]);
	printf("%d",a[v[v.size()-1]]);
	return 0;
}

T2

题目大意:给出一张有边权的图,有两问:
1.求出边权为正的点的连通块大小,连通块中最小的id,连通块中最小的边权。
2.边权为负即为,连接这两个点的代价(为正代价为0),对于不存在的边连接代价是1e4,问将所有点连接起来的,最小代价是多少。
n , m < = 1 e 5 n,m<=1e5 n,m<=1e5

两问完全没有关系…
第一问直接并查集写一写,注意一下合并的id顺序是,从大的往小的合并即可,剩下的模拟实现。
第二问把一个连通块当成一个点,直接跑Kruskal最小生成树就没了。

C++代码实现如下:

#include<bits/stdc++.h>
#define maxn 1000005
#define ll long long
#define ins insert
#define inf 1e9
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;

inline int read()
{
	int x=0,w=1; char c=getchar();
	while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
	while(c<='9'&&c>='0') x=(x<<1)+(x<<3)+c-'0',c=getchar();
	return w==1?x:-x;
}

int n,m,mn[maxn],sz[maxn],f[maxn],bel[maxn],U[maxn],V[maxn],W[maxn],cnt,c2,ff[maxn];
struct node{int a,b,c;}p[maxn];
struct node2{int u,v,w;}e[maxn];

inline bool cmp(node a,node b)
{
	if(a.a!=b.a) return a.a>b.a;
	else if(a.b!=b.b) return a.b>b.b;
	else return a.c<b.c;
}

inline bool cmp2(node2 a,node2 b){return a.w<b.w;}

inline int F(int x)
{
	if(f[x]==x) return x;
	return f[x]=F(f[x]);
}

inline int FF(int x)
{
	if(ff[x]==x) return x;
	return ff[x]=FF(ff[x]);
}

int main()
{
	freopen("t1.in","r",stdin);
	n=read(); m=read(); rep(i,1,n) f[i]=i,sz[i]=1,ff[i]=i,mn[i]=inf;
	rep(i,1,m)
	{
		U[i]=read(); V[i]=read(); W[i]=read();
		if(W[i]>=0)
		{
			int tx=F(U[i]),ty=F(V[i]);
			if(tx!=ty)
			{
				if(tx<ty) f[ty]=tx,sz[tx]+=sz[ty],mn[tx]=min(mn[tx],min(mn[ty],W[i]));
				else f[tx]=ty,sz[ty]+=sz[tx],mn[ty]=min(mn[ty],min(mn[tx],W[i]));
			}
			else mn[tx]=min(mn[tx],W[i]);
		}
	}
	rep(i,1,n) if(i==F(i))
	{
		p[++cnt].a=mn[i],p[cnt].b=sz[i],p[cnt].c=i;
		if(mn[i]==inf) p[cnt].a=0;
	}
	sort(p+1,p+cnt+1,cmp);
	rep(i,1,cnt)
	{
		if(i!=cnt) printf("%d-%d ",p[i].c,p[i].a);
		else printf("%d-%d",p[i].c,p[i].a);
	}
	puts("");
	
	rep(i,1,m)
	{
		if(W[i]<0)
		{
			int tx=F(U[i]),ty=F(V[i]);
			if(tx!=ty) e[++c2]={tx,ty,-W[i]};
		}
	}
	sort(e+1,e+c2+1,cmp2); ll ans=0,nw=0;
	rep(i,1,n) if(F(i)==i) nw++; nw--;
	rep(i,1,c2)
	{
		int tx=FF(e[i].u),ty=FF(e[i].v);
		if(tx!=ty) {ans+=e[i].w,ff[tx]=ty,nw--;}
	}
	cout<<(ll)ans+10000*nw<<endl;
	return 0;
}

(其实也只是单纯的大模拟而已…)

T3

题目大意:两个人玩游戏,每次一个人操作让自己的分数+a[i],不是轮流操作,每个人的一次操作要求,操作完后自己的分数不低于另外一个人。给出了a数组长度为n,问有多少种合法的游戏序列?
n < = 100000 , a [ i ] < = 3 n<=100000,a[i]<=3 n<=100000,a[i]<=3

考虑 d p [ i ] [ j ] dp[i][j] dp[i][j]表示选完了前i个数,第一个人比第二个人多j分的方案数
因为 − 3 < = j < = 3 -3<=j<=3 3<=j<=3,所以我们把j全部+3来避免负数。
然后对于转移的情况分类讨论就做完了。(情况很裸,大家看看代码就明白了)

#include<bits/stdc++.h>
#define maxn 1000005
#define ll long long
#define ins insert
#define inf 1e9
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;

inline int read()
{
	int x=0,w=1; char c=getchar();
	while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
	while(c<='9'&&c>='0') x=(x<<1)+(x<<3)+c-'0',c=getchar();
	return w==1?x:-x;
}

const ll mod=1000000007;
ll dp[maxn][10],ans,n,a[maxn];

inline ll ADD(ll

以上是关于PAT顶级2021-09题解的主要内容,如果未能解决你的问题,请参考以下文章

PAT乙级全套超详细题解建议收藏

(PAT详细题解)PAT甲级--Cars on Campus

pat 顶级 1001 Battle Over Cities - Hard Version (35 分)

PAT 1049. 数列的片段和

PAT乙级题库“傻瓜”题解之跟奥巴马一起编程

PAT-乙级-1049 数列的片段和