6.30模拟赛

1.盘子序列(disk)

【题目描述】

个盘子。盘子被生产出来后,被按照某种顺序摞在一起。初始盘堆中如果一

个盘子比所有它上面的盘子都大,那么它是安全的,否则它是危险的。称初始盘堆为

A,另外有一个开始为空的盘堆 B。为了掩盖失误,生产商会对盘子序列做一些“处

理”,每次进行以下操作中的一个:(1)最上面的盘子放到最上面;(2)最上

面的盘子给你。在得到所有个盘子之后,你需要判断初始盘堆里是否有危险的盘子。

【输入格式】

输入文件包含多组数据(不超过 10 组)

每组数据的第一行为一个整数 n

接下来个整数,第个整数表示你收到的第个盘子的大小

【输出格式】

对于每组数据,如果存在危险的盘子,输出”J”,否则输出”Y”

【样例输入】

3

2 1 3

3

3 1 2

【样例输出】

Y

【数据范围】

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.四轮车

【题目描述】

在地图上散落着个车轮,小想用它们造一辆车。要求如下:

  1. 一辆车需要四个车轮,且四个车轮构成一个正方形
  1. 车轮不能移动你需要计算有多少种造车的方案(两个方案不同当且仅当所用车轮不全相同,坐标相同的两个车轮视为不同车轮)。

【输入格式】

第一行一个整数 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.点名

【题目描述】

班的体育课上,同学们常常会迟到几分钟,但体育老师的点名却一直很准时。

老师只关心同学的身高,他会依次询问当前最高的身高,次高的身高,第三高的身高,

等等。在询问的过程中,会不时地有人插进队伍里。你需要回答老师每次的询问。

【输入格式】

第一行两个整数 n m,表示先后有个人进队,老师询问了

第二行个整数,第个数 Ai 表示第个进入队伍的同学的身高为 Ai

第三行个整数,第个数 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
",qd.top());
    }
    fclose(stdin);fclose(stdout);
    return 0;
}

自己选的路,跪着也要走完!!!

原文地址:https://www.cnblogs.com/wsdestdq/p/7101482.html