6.30模擬賽
1.盤子序列(disk)
【題目描述】
有 n 個盤子。盤子被生產出來後,被按照某種順序摞在一起。初始盤堆中如果一
個盤子比所有它上面的盤子都大,那麽它是安全的,否則它是危險的。稱初始盤堆為
A,另外有一個開始為空的盤堆 B。為了掩蓋失誤,生產商會對盤子序列做一些“處
理”,每次進行以下操作中的一個:(1)將 A 最上面的盤子放到 B 最上面;(2)將 B 最上
面的盤子給你。在得到所有 n 個盤子之後,你需要判斷初始盤堆裏是否有危險的盤子。
【輸入格式】
輸入文件包含多組數據(不超過 10 組)
每組數據的第一行為一個整數 n
接下來 n 個整數,第
【輸出格式】
對於每組數據,如果存在危險的盤子,輸出”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; }
自己選的路,跪著也要走完!!!
6.30模擬賽