1. 程式人生 > >6.30模擬賽

6.30模擬賽

ret 繼續 集合 ++ 新元素 != fff utility 文件包含

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 想用它們造一輛車。要求如下:

  1. 一輛車需要四個車輪,且四個車輪構成一個正方形
  1. 車輪不能移動你需要計算有多少種造車的方案(兩個方案不同當且僅當所用車輪不全相同,坐標相同的兩個車輪視為不同車輪)。

【輸入格式】

第一行一個整數 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模擬賽