PTA | 程序设计类实验辅助教学平台 (pintia.cn)
刚开始写的三个for循环:
范围是1e5,写三个for循环肯定超了。
AC
也就是我们需要先找到a[i]左边([i,i-1])的最大值mn,a[i]右边的([i+1,n])最小值mx
如果a[i]大于mn并且小于mx,那么a[i]就可能是主元,先把a[i]加入到栈顶。
这时候我需要继续找下一个主元。
但是在此之前我们还需要再做一个步骤:
#include<bits/stdc++.h>
using namespace std;
#define N 100005
int a[N], mn[N], ans[N];
int t;//栈顶下标
int main(){
int n;
scanf("%d", &n);
for(int i = 1; i <= n; ++ i){
scanf("%d", a + i);
mn[i] = max(mn[i - 1], a[i]);//第一次循环的处理
}
int mx = 1e9;
//第二次循环的处理
for(int i = n; i >= 1; -- i){
if(mn[i - 1] < a[i] && a[i] < mx) //满足条件的可能是主元,加入到栈里
ans[++ t] = a[i];//加入到栈
mx = min(mx, a[i]); //更新mx为当前元素和mx之间的较小值
}
sort(ans + 1, ans + t + 1);//排序
printf("%d\n", t); //输出栈中元素的个数,即主元的个数
if(!t) printf("\n");//恶心的数据点 最后一行必须换行,不然会有一个测试点没法过
for(int i = 1; i <= t; ++ i)
{
printf("%d", ans[i]);
if(i < t) printf(" ");
}
return 0;
}
选择主元的标准是左边的所有元素都小于等于它,右边的所有元素都大于等于它。因此,对于数组a中的每个元素a[i],我们需要找到它左边最大的数和右边最小的数。
mn[i]数组用于存储每个位置i左边最大的数。在第一次循环中,我们初始化mn[1]为a[1],然后对于每个位置i(从2到n),mn[i]被设置为max(mn[i - 1], a[i])。这样,mn[i]就代表了从a[1]到a[i - 1]中的最大值。
二刷
如果序列经过排序之后相对位置的值发生不变,说明这个数相对稳定,即可能前面的数不比它大,后面的数不比它小。那么这个数很可能是住院,那么我们就继续判断,如果这个数比它前面的数都大,那么这个数就是主元。
坑点: 如果说给定的序列中没有主元,即主元个数为0,那么我们会输出0,但是题目要求最后输出两行,所以我们还要输出一个空行,否则会丢分:
#include<bits/stdc++.h>
using namespace std;
// int a[10010],b[10010];
vector<int>ans;
int max_n=-1;
int main()
{
int n=0;cin>>n;
vector<int>a(n,0),b(n,0);
for(int i=0;i<n;i++)
{
cin>>a[i];
b[i]=a[i];
}
sort(b.begin(),b.end());
for(int i=0;i<n;i++)
{
if(a[i]==b[i]&&a[i]>=max_n)
ans.push_back(a[i]);
max_n=max(max_n,a[i]);
}
cout<<ans.size()<<endl;
if(ans.size()) //如果主元个数不为0
{
for(int i=0;i<ans.size();i++)
{
cout<<ans[i];
if(i+1!=ans.size())cout<<" ";
}
}
//否则主元个数为0
cout<<endl; //输出一个空行
return 0;
}