清北第二套题
【问题描述】
栈是一种强大的数据结构,它的一种特殊功能是对数组进行排序。例如,借助一个栈,依次将数组1,3,2按顺序入栈或出栈,可对其从大到小排序:
1入栈;3入栈;3出栈;2入栈;2出栈;1出栈。
在上面这个例子中,出栈序列是3,2,1,因此实现了对数组的排序。
遗憾的是,有些时候,仅仅借助一个栈,不能实现对数组的完全排序。例如给定数组2,1,3,借助一个栈,能获得的字典序最大的出栈序列是3,1,2:
2入栈;1入栈;3入栈;3出栈;1出栈;2出栈。
请你借助一个栈,对一个给定的数组按照出栈顺序进行从大到小排序。当无法完全排序时,请输出字典序最大的出栈序列。
【输入格式】
输入共行。
第一行包含一个整数,表示入栈序列长度。
第二行包含个整数,表示入栈序列。输入数据保证给定的序列是到n的全排列,即不会出现重复数字。
【输出格式】
仅一行,共个整数,表示你计算出的出栈序列。
【样例输入】
3
2 1 3
【样例输出】
3 1 2
【样例解释】
这回山里有座塔。
【数据规模与约定】
对于30%的数据,1<=N<=10^3。
对于60%的数据,1<=N<=10^5。
对于100%的数据,1<=N<=10^6。
题解:感觉自己的代码有种超时的即视感,然而并没有。先找最大的,前面的都入栈。然后找第二大,如果在栈顶,出栈,如果没有,比较栈顶元素和maxn(没入栈的元素)谁大,如果栈顶元素大,出栈,反之将在maxn之前的元素全部入栈,继续重复前面操作。直到栈空。
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #define N 1000100 using namespace std; int n,top(0),maxn; int a[N],zh[N]; bool f[N]={0}; void xx() { while (f[maxn]) maxn--; while (zh[top]>maxn&&top) { printf("%d ",zh[top]); top--; while (f[maxn]) maxn--; } } int main() { freopen("haha.in","r",stdin); freopen("haha.out","w",stdout); scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&a[i]); maxn=n; for (int i=1;i<=n;i++) { if (a[i]!=maxn) zh[++top]=a[i],f[a[i]]=1; if (a[i]==maxn) { f[maxn]=1; printf("%d ",a[i]); xx(); } } while (top) { printf("%d ",a[top]); top--; } fclose(stdin); fclose(stdout); return 0; }
【问题描述】
小Q对计算几何有着浓厚的兴趣。他经常对着平面直角坐标系发呆,思考一些有趣的问题。今天,他想到了一个十分有意思的题目:
首先,小Q会在轴正半轴和轴正半轴分别挑选个点。随后,他将轴的点与轴的点一一连接,形成条线段,并保证任意两条线段不相交。小Q确定这种连接方式有且仅有一种。最后,小Q会给出个询问。对于每个询问,将会给定一个点,请回答线段OP与条线段会产生多少个交点?
小Q找到了正在钻研数据结构的你,希望你可以帮他解决这道难题。
【输入格式】
第行包含一个正整数,表示线段的数量;
第行包含个正整数,表示小Q在轴选取的点的横坐标;
第行包含个正整数,表示小Q在轴选取的点的纵坐标;
第4行包含一个正整数,表示询问数量;
随后行,每行包含两个正整数,表示询问中给定的点的横、纵坐标。
【输出格式】
共行,每行包含一个非负整数,表示你对这条询问给出的答案。
【样例输入】
3
4 5 3
3 5 4
2
1 1
3 3
【样例输出】
0
3
【样例解释】
然后塔里啥都没有。
【数据规模与约定】
对于50%的数据,1<=n,m<=2*10^3。
对于100%的数据,1<=n,m<=2*10^5,坐标范围<=10^8。
题解:由于n条线段互不相交,因此将x和y从小到大排序,一一对应形成线段。二分答案,若此时点P与原点形成的线段与此时的第mid条线段相交,则一定与在mid之前的线段相交。判断是否相交时,可以将P点的横坐标第mid条直线的解析式中求出y来,将y与P点的纵坐标进行比较,若y比P点的纵坐标大,说明两线段相交,反之则不相交。
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<cmath> #define N 200100 #define ll long long using namespace std; int n,m,ans; double x[N],y[N]; bool check(int k,double x1,double y1) { if (k==0) return 0; double Y=-y[k]/x[k]*x1+y[k];//求把此时的横坐标代入第k条线段对应的纵坐标 return Y<y1; } int main() { freopen(".in","r",stdin); freopen(".out","w",stdout); scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%lf",&x[i]); for (int i=1;i<=n;i++) scanf("%lf",&y[i]); sort(x+1,x+n+1);//小的x对应小的y,保证线段不相交 sort(y+1,y+n+1); scanf("%d",&m); for (int i=1;i<=m;i++) { double xx,yy; scanf("%lf%lf",&xx,&yy); int l=0,r=n; while (l<=r) { int mid=(l+r)>>1; if (check(mid,xx,yy)) ans=mid,l=mid+1; else r=mid-1; } cout<<ans<<endl; } fclose(stdin); fclose(stdout); return 0; }