P2649 游戏预言

# 游戏预言

## 题目描述

John 和朋友们在玩纸牌游戏,他们一共有 $m$ 个人(包括 John)。他们的纸牌比较特殊,一共有 $n \times m$ 张牌,牌号分别为 $1,2,\dots,n \times m$,没有牌号相同的牌。每个人先拿到 $n$ 张牌,然后,每一轮,每个人出一张牌,谁最大则谁赢得这一轮。现在已知 John 手中的 $n$ 张牌,计算他最少能赢得多少轮。

## 输入格式

第一行为两个整数 $m$ 和 $n$。

第二行有 $n$ 个正整数,表示 John 手中的 $n$ 张牌的数值。

## 输出格式

仅一个整数,表示 John 最少能赢的次数。

## 样例 #1

### 样例输入 #1

```
2 5
1 7 2 10 9
```

### 样例输出 #1

```
2
```

## 样例 #2

### 样例输入 #2

```
6 11
62 63 54 66 65 61 57 56 50 53 48
```

### 样例输出 #2

```
4
```

## 提示

对于 $100 \%$ 的数据,$2 \le m \le 20$,$1 \le n \le 50$。

 

首先思考一下:

题目要的是John最少赢几局,那么我们代入对方的视角莱想一想:如果你跟John打牌,你怎么让他赢的次数少呢?假设John出了一张5,你手上有一张6,这时候有两种情况:

①不出这张6,让John赢一次,如果John后面的牌全都≥6那么这张6废了

②出这张6,让John输一次,后面John出什么牌只要我有比他大的就压,比他大的牌出完了他就赢一局

那么按照题目意思,要让John输的次数最多

那么代码思路就出来了,双方都从大到小出牌,遇上自己的牌就加入自己的牌堆(cnt++),如果你有牌而且比John最大的牌还大,那就压上(cnt--);如果比John大的牌出完了就是他赢了(cnt<1,也就是比John的牌更大的牌不足一张)

那么我们需要用桶排序,确认我的牌和John的牌的数量,因为我的牌从大到小排列,只要John最大的牌比我的牌小,那么他后面的所有牌都比我小(废话,但是写进代码里很有用)

下面是代码:

 

#include<iostream>
using namespace std;
//最多有50张牌,从1开始存,所以数组开到51
int a[51];
//最多有20个人,20*50=1000,防止越界就开到1001
bool b[1001];
int main(){
    //cnt记下我比John大的牌的数目
    //ans记录john赢的次数
    int n,m,cnt=0,ans=0;
    cin>>n>>m;
    //桶排序,因为题目说了不会有重复的牌所以不用担心桶排序吞掉牌
    for(int i=1;i<=m;i++){
        cin>>a[i];
        //把John有的牌标记为1
        b[a[i]]=1;
    }
    //从牌堆最后一张开始往前推,其实就是从大到小出牌的模拟
    m*=n;
    for(int i=m;i>=1;i--){
        //如果这张牌是我的,那么放进我的牌堆
        //如果上一张是John的,那也被结算了,要么我有比他还大的牌,要么他赢一次
        if(b[i]==0){
            cnt++;
        }
        //如果这张牌是他的,判断我有没有比他大的牌,如果cnt>=1说明我有一张牌比他这张更大
        //根据我们的思路,我们要把这张牌出了,也就是cnt--
        else if(cnt>=1)cnt--;
        //如果cnt<1说明我没牌比他大,也就是比他大的牌全出完了,那他就赢了这一局
        //ans++
        else ans++;
    }
    //输出ans
    cout<<ans;
    return 0;
}

 

posted @ 2022-09-20 23:16  丷Ghost丷  阅读(48)  评论(0)    收藏  举报