2017-6-11 NOIP模拟赛
盘子序列
【题目描述】
有 n 个盘子。盘子被生产出来后,被按照某种顺序摞在一起。初始盘堆中如果一
个盘子比所有它上面的盘子都大,那么它是安全的,否则它是危险的。称初始盘堆为
A,另外有一个开始为空的盘堆 B。为了掩盖失误,生产商会对盘子序列做一些“处
理” ,每次进行以下操作中的一个:(1)将 A 最上面的盘子放到 B 最上面;(2)将 B 最上
面的盘子给你。 在得到所有n个盘子之后, 你需要判断初始盘堆里是否有危险的盘子。
【输入格式】
输入文件包含多组数据(不超过 10 组)
每组数据的第一行为一个整数 n
接下来 n 个整数,第 i 个整数表示你收到的第 i 个盘子的大小
【输出格式】
对于每组数据,如果存在危险的盘子,输出”J”,否则输出”Y”
【样例输入】
3
2 1 3
3
3 1 2
【样例输出】
Y
J
【数据范围】
20%的数据保证 n<=8
80%的数据保证 n<=1,000
100%的数据保证 1<=n<=100,000,0<盘子大小<1,000,000,000 且互不相等
模拟,考试的时候想着双栈排序那道题,就考虑到,当且仅当i<j<k&&a[j]<a[k]<a[i]是不能用单栈排序(i位于三者最底层),好像和这个题是同样的道理,所以就这么写出来了,没多想,考完顿悟了,这个做法复杂度O(n^2),还不如开个栈模拟
/*考完试一气之下写的这个丑代码我也不想说什么了,感觉像在乱搞*/ #include<iostream> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; #define maxn 100010 int n,top1,top2,top3; struct node{ int num,rank,id; }a[maxn],b[maxn]; int cmp1(node x,node y){ return x.num>y.num; } int cmp2(node x,node y){ return x.id<y.id; } int main(){ freopen("disk.in","r",stdin); freopen("disk.out","w",stdout); while(scanf("%d",&n)!=EOF){ bool flag=0; memset(a,0,sizeof(a));top1=0;top2=0;top3=1; for(int i=1;i<=n;i++)scanf("%d",&a[++top1].num),a[top1].id=i; sort(a+1,a+n+1,cmp1); for(int i=1;i<=n;i++)a[i].rank=i; sort(a+1,a+n+1,cmp2); while(top1>=1){ int t1=top1,t2=top2,t3=top3; while(top2!=0&&b[top2].rank==top3){ top3++;top2--; } if(a[top1].rank==top3){ top3++;top1--; } else{ while(a[top1].rank!=top3&&b[top2].rank!=top3){ if(top1<=0){ flag=1;break; } b[++top2]=a[top1--]; } } if(t1==top1&&t2==top2&&t3==top3){ break; } if(flag==1)break; } while(top2!=0&&b[top2].rank==top3){ top3++;top2--; } if(flag==1)printf("J\n"); else if(top3!=n+1){ printf("J\n"); } else printf("Y\n"); } }
四轮车
【题目描述】
在地图上散落着 n 个车轮,小 J 想用它们造一辆车。要求如下:
1. 一辆车需要四个车轮,且四个车轮构成一个正方形
2. 车轮不能移动
你需要计算有多少种造车的方案 (两个方案不同当且仅当所用车轮不全相同, 坐
标相同的两个车轮视为不同车轮) 。
【输入格式】
第一行一个整数 n
接下来 n 行,每行两个整数 x y,表示在(x,y)处有一个车轮
【输出格式】
一行一个整数,表示方案数
【样例输入】
9
0 0
1 0
2 0
0 2
1 2
2 2
0 1
1 1
2 1
【样例输出】
6
【数据范围】
30%的数据保证 n ≤ 30
100%的数据保证 1 ≤ n ≤ 1000;|x|,|y| < 20000
考试的时候把这题当成数学题了,上来就考虑正方形的性质,什么四条边相等啊,临边垂直啊,对角线垂直啊,然后就开始写了,也没觉得有什么不妥,但是这个方法超级麻烦,写完之后样例过了,代码丑的要死,结果爆空间。
正解是枚举两个点判断其余的两个点是否存在(只考虑枚举到的点为对角线上的点的情况),问题很好解决了
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 10010 using namespace std; int n,ans[maxn]; int x1,x2,x3,x4,y1,y2,y3,y4,xx[maxn],yy[maxn],p1,p2; struct node{ int x,y; }P[maxn]; int cmp(node a,node b){ return a.x<b.x; } int Abs(int a){ return a<0?(-a):a; } void add(){ ans[1]++; for(int i=1;i<=ans[0];i++) if(ans[i]>9){ ans[i]%=10; ans[i+1]++; } if(ans[ans[0]+1])ans[0]++; } void Cal(int i,int j){ x1=xx[i]; y1=yy[i]; x2=xx[j]; y2=yy[j]; int a=Abs(y1-y2),b=Abs(x1-x2); int c=Abs(a-b); if(c%2) x3=x4=y3=y4=0; else{ c>>=1; if(a<b){ x3=x1+c; y3=y2+c; x4=x2-c; y4=y1-c; } else{ x3=x1-c; y3=y2-c; x4=x2+c; y4=y1+c; } } } bool Judge(){ if(!x3&&!x4&&!y3&&!y4) return 0; int falg=0,flag=0; p1=lower_bound(xx+1,xx+1+n,x3)-xx; p2=upper_bound(xx+1,xx+1+n,x3)-xx; for(int i=p1;i<p2;i++){ if(xx[i]!=x3) return 0; if(yy[i]==y3){ falg=1; break; } } p1=lower_bound(xx+1,xx+1+n,x4)-xx; p2=upper_bound(xx+1,xx+1+n,x4)-xx; for(int i=p1;i<p2;i++){ if(xx[i]!=x4) return 0; if(yy[i]==y4){ flag=1; break; } } return falg&&flag; } int main() { freopen("car.in","r",stdin); freopen("car.out","w",stdout); scanf("%d",&n); ans[0]=1; for(int i=1;i<=n;i++) scanf("%d%d",&P[i].x,&P[i].y); sort(P+1,P+1+n,cmp); for(int i=1;i<=n;i++){ xx[i]=P[i].x; yy[i]=P[i].y; } for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++){ if(yy[i]>=yy[j]) continue; Cal(i,j); if(Judge()) add(); } for(int i=ans[0];i>=1;i--) printf("%d",ans[i]); return 0; }
点名
【题目描述】
在J班的体育课上, 同学们常常会迟到几分钟, 但体育老师的点名却一直很准时。
老师只关心同学的身高, 他会依次询问当前最高的身高, 次高的身高, 第三高的身高,
等等。在询问的过程中,会不时地有人插进队伍里。你需要回答老师每次的询问。
【输入格式】
第一行两个整数 n m,表示先后有 n 个人进队,老师询问了 m 次
第二行 n 个整数,第 i 个数 Ai 表示第 i 个进入队伍的同学的身高为 Ai
第三行 m 个整数,第 j 个数 Bj 表示老师在第 Bj 个同学进入队伍后有一次询问
【输出格式】
m 行,每行一个整数,依次表示老师每次询问的答案。数据保证合法
【样例输入】
7 4
9 7 2 8 14 1 8
1 2 6 6
【样例输出】
9
9
7
8
【样例解释】
(9){No.1 = 9}; (9 7){No.2 = 9}; (9 7 2 8 14 1){No.3 = 7; No.4 = 8}
【数据范围】
40%的数据保证 n ≤ 1000
100%的数据保证 1 ≤ m ≤ n ≤ 30000;0 ≤ Ai < 2^32
看到这个题,纠结于死难写死难写的主席树。
黄学长用的方法和树毛线关系也没有,我学了来
维护前K大的大根堆 A
维护其余的小根堆 B
插入:A.insert() B.insert(A.pop())
询问:ans = A.top(); A.insert(B.pop())
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> typedef int real; #define int long long #define pa pair<int,int> #define inf 1000000000 using namespace std; int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } priority_queue<int,vector<int>,greater<int> >q1; priority_queue<int,vector<int> >q2; int n,m; int a[30005],b[30005]; real main() { freopen("rollcall.in","r",stdin); freopen("rollcall.out","w",stdout); n=read();m=read(); for(int i=1;i<=n;i++)a[i]=read(); for(int i=1;i<=m;i++)b[i]=read(); for(int t=1;t<=m;t++) { for(int j=b[t-1]+1;j<=b[t];j++) { q2.push(a[j]); q1.push(q2.top());q2.pop(); } q2.push(q1.top());q1.pop(); printf("%I64d\n",q2.top()); } return 0; }