1.盘子序列(disk)
【题目描述】
有 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 且互不相等
思路:
STL~ 栈。。。
题目告诉我们手中收到盘子的顺序,让我们来推断A堆的盘子顺序,从而判断A堆是否是安全的,我们可以换一种思路,我们假设A堆是安全的,那么如果通过操作能得到收盘子的顺序,那么就是安全的,否则是危险的!!!
如果当前堆是安全的,那么在下面的盘子一定比上面的大!!
仔细阅读,不难发现题目中的两个操作就是进栈和出栈的操作,所以我们将盘子从小到大一边压栈一边与出栈顺序比较,如果相同就出栈,否则继续新元素继续进栈,直到相同在出栈,我们会发现如果最后栈中的元素数是>1时,说明不能得到当前所给的出栈顺序,所以不安全,否则,安全。。
上代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<stack> using namespace std; const int maxx = 100003; int n,dish[maxx],A[maxx],num,tot,step[maxx]; stack<int>s; int main() { freopen("disk.in","r",stdin); freopen("disk.out","w",stdout); while(scanf("%d",&n)!=EOF) { while(!s.empty()) s.pop(); for(int i=1; i<=n; i++) { scanf("%d",&dish[i]); step[i] = dish[i]; } sort(step+1,step+n+1); int num = 1,tot = 1; s.push(step[num]); while(tot<=n && num<=n) { int top = s.top(); if(top == dish[tot]) tot++,s.pop(); else s.push(step[num+1]),num++; if(s.empty()) s.push(step[num+1]),num++; } if(s.size()>1) cout<<"J"<<endl; else cout<<"Y"<<endl; } fclose(stdin),fclose(stdout); return 0; }
2.四轮车
【题目描述】
在地图上散落着 n 个车轮,小 J 想用它们造一辆车。要求如下:
- 一辆车需要四个车轮,且四个车轮构成一个正方形
- 车轮不能移动你需要计算有多少种造车的方案(两个方案不同当且仅当所用车轮不全相同,坐标相同的两个车轮视为不同车轮)。
【输入格式】
第一行一个整数 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
思路:
我们确定正方形两个点,去枚举正方形的另外两个点,我们知道两点的坐标,去表示另两点的坐标,但是正方形可能是与x、y轴平行的,也可能不是,所以我们分三种情况讨论。。。
pair<int,int>ZB, first表示该点的横坐标,second表示纵坐标,set一一映射,判断点是否存在轮胎
上代码:
#include<iostream> #include<cstdio> #include<cmath> #include<utility> #include<cstdlib> #include<set> using namespace std; typedef pair<int,int>ZB; ZB jz[1003],a1,a2,step; int n,x,y,a,b,c,d; set<ZB>S; long long ans; void solve(int i,int j) { a=jz[i].first,b=jz[i].second,c=jz[j].first,d=jz[j].second; if(a == c) { //已知坐标的横坐标相等 ,在同一列 a1.first=a+abs(d-b),a1.second=b,a2.first=c+abs(d-b),a2.second=d; if(S.count(a1) && S.count(a2)) ans++;//S.count()如果集合中有这个元素返回1,否则返回0 a1.first=a-abs(d-b),a1.second=b,a2.first=c-abs(d-b),a2.second=d; if(S.count(a1) && S.count(a2)) ans++; } else if(b == d) { //已知坐标的纵坐标相等,在同一行 a1.first=a,a1.second=b+abs(a-c),a2.first=c,a2.second=d+abs(a-c); if(S.count(a1) && S.count(a2)) ans++; a1.first=a,a1.second=b-abs(a-c),a2.first=c,a2.second=d-abs(a-c); if(S.count(a1) && S.count(a2)) ans++; } else { //正方形与x、y轴不平行 a1.first=a-abs(d-b),a1.second=d+abs(a-c),a2.first=a+abs(a-c),a2.second=d+abs(d-b); if(S.count(a1) && S.count(a2)) ans++; a1.first=a+abs(d-b),a1.second=d-abs(a-c),a2.first=a-abs(a-c),a2.second=d-abs(d-b); if(S.count(a1) && S.count(a2)) ans++; } } int main() { //freopen("car10.in","r",stdin); //freopen("car.out","w",stdout); scanf("%d",&n); for(int i=1; i<=n; i++) { scanf("%d%d",&jz[i].first,&jz[i].second); step.first = jz[i].first, step.second = jz[i].second; S.insert(step); } for(int i=1; i<=n; i++) { for(int j=1; j<=n; j++) { if(i == j) continue; solve(i,j); } } printf("%d",ans/8);//每个正方形有四个点,一条边可扩展2个正方形,所以答案/8 fclose(stdin); fclose(stdout); return 0; }
3.点名
【题目描述】
在 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 < 232
思路:
1.考场暴力sort,70分(当然,这是在用long long的情况下,数据太TM坑人了)
2.大根堆与小根堆的巧妙结合(AC)
3.主席树(AC,可是偶不会2333。。。)
大根堆与小根堆的巧妙结合:
一个小根堆q1,一个大根堆q2
q2维护当前最小的k个值
所以每次的答案就是q2的堆顶
对于每次询问,
枚举上一次入队到这一次入队的人
向q2中加入这个人的高度,q1中加入q2的堆顶,删除q2堆顶
即加入新的,删除最大的,保持q2中始终是当前最小的k个
因为这个k是上一次询问的k
所以最后把q1的堆顶加入q2,删除q1堆顶
所以q1是小根堆
坑:数据 2^32 是long long
上代码:
#include<iostream> #include<cstdio> #include<queue> using namespace std; priority_queue<long long,vector<long long>,greater<int> >qx; priority_queue<long long>qd; long long n,m,hight[30003],ask[30003]; int main() { freopen("rollcall10.in","r",stdin); freopen("rollcall.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1; i<=n; i++) { scanf("%d",&hight[i]); } for(int i=1; i<=m; i++) { scanf("%d",&ask[i]); } for(int i=1; i<=m; i++) { for(int j=ask[i-1]+1; j<=ask[i]; j++) { qd.push(hight[j]); qx.push(qd.top()),qd.pop(); } qd.push(qx.top()),qx.pop(); printf("%I64d\n",qd.top()); } fclose(stdin);fclose(stdout); return 0; }
自己选的路,跪着也要走完!!!