• Vijos 纸牌


    题目网址

    https://vijos.org/d/Randle/p/5a0011e1d3d8a10a532d6d71

    题目描述

           在桌面上放着n张纸牌,每张纸牌有两面,每面都写着一个非负整数。你的邪王真眼可以看到所有牌朝上的一面和朝下的一面写的数字。现在你需要将一些牌翻过来,使得所有牌朝上的一面中,至少有一半(≥n/2)的数字是一样的。请你求出最少需要翻几张牌,或者判断无解。注意:在翻牌的时候,你不能把牌扔掉,不能偷偷把别的牌放进来,也不能用笔涂改牌上面的数字。

    输入格式

    第一行包含一个整数n,表示牌的数量;接下来n行,每行两个非负整数ai, bi,表示每张牌上写的两个数字,ai对应朝上的一面,bi对应朝下的一面。

    输出格式

    如果有解,则输出一个整数,表示最少的翻牌次数,否则输出Impossible。

    样例

    样例输入1

    3
    1 2
    2 1
    3 4

    样例输出1

    1

    样例输入2

    3
    1 2
    3 4
    5 6

    样例输出2

    Impossible

    样例说明

    样例解释1

    把第一张牌翻过来,那么就有两个2一个3朝上了,2的数量超过了半数。

    样例解释2

    所有数字都只有一个,因此相同的数字数超过半数是不可能的。

    数据范围

    ai,bi<=10^9,n<=3*10^5
    对所有数据,有n>0,ai, bi≥0。

    题解

    本题扫一眼会觉得很简单,但是再扫一眼,就会发现,真的是很烦。

    首先,本题很难枚举翻哪一张牌,因为可以同时翻好几张牌。那么,本题的难点就是在于问题的转化。

    不好枚举翻哪一张牌,那么我们就枚举哪一种牌可以翻。

    如样例1,出现次数最多的是2,那么我们就可以枚举出翻含有2的牌的次数。

    但是本题还有一个细节:出现次数最多的数字一定只需要翻最少次数吗?当然不一定,这种情况一定要考虑。

    另外,本题还用到了离散化,离散化可以用map来实现

    再把思路整理一遍

    1.读入n

    2.进行n次操作,每次读入ai和bi,利用map,将ai和bi分开进行离散化处理

    注意:如果ai和bi的值相等,那么只能存储一次,以为这种牌无论翻不翻都一样

    3.读入ai和bi的同时,将他们存放在一个数组中,并在读入结束后对该数组(用A[]表示)进行排序(理论上该排序没有任何意义,但是加上以后确实能快一点)

    4.从1开始枚举A[]中左右的元素,对其出现次数进行判断,看能否满足超过一半的条件。如果可以,计算出它需要的最少次数,并对所有可行方案求最小值

    代码

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <cstdlib>
     4 #include <iostream>
     5 #include <algorithm>
     6 #include <bits/stdc++.h>
     7 using namespace std;
     8 
     9 const int N=300005;
    10 
    11 map<int,int> M0,M1;
    12 int A[2*N];
    13 int n,m,a[N],b[N],ans=N;
    14 
    15 void init()
    16 {
    17     scanf("%d", &n);
    18     for (int i=1; i<=n; i++)
    19     {
    20         scanf("%d %d",&a[i], &b[i]);
    21         if (a[i]==b[i]) M0[a[i]]++;//记录a的次数
    22         else M0[a[i]]++, M1[b[i]]++;
    23         A[++m]=a[i];//将所有出现的数都放在A[]中
    24         A[++m]=b[i];
    25     }
    26     sort(A+1,A+m+1);
    27 } 
    28 
    29 void work()
    30 {
    31     for (int i=1; i<=m; i++)//枚举在最终要翻的牌面数字
    32     {
    33         int x=M0[A[i]],y=M1[A[i]];
    34         if (x+y>=(n+1)/2)
    35             ans=min(ans,max((n+1)/2-x,0));
    36     }
    37     if (ans==N)printf("Impossible
    ");
    38     else printf("%d
    ",ans);
    39     return;
    40 }
    41 
    42 int main()
    43 {
    44     init();
    45     work();
    46     return 0;
    47 }

    出处:https://www.cnblogs.com/yujustin/

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

    温馨提示:尽量使用版本较高的浏览器,并打开极速模式。

  • 相关阅读:
    是否需要有代码规范
    小学四则运算生成程序(支持分数)总结
    HDU 4035 Maze 期望dp
    UVA
    HDU 3853 LOOPS 期望dp
    POJ 2096 Collecting Bugs 期望dp
    HDU 4405 Aeroplane chess 期望dp
    Codeforces Round #341 (Div. 2) E. Wet Shark and Blocks dp+矩阵加速
    HDU 4616 Game 树形dp
    HDU 4126 Genghis Khan the Conqueror 最小生成树+树形dp
  • 原文地址:https://www.cnblogs.com/yujustin/p/9743667.html
Copyright © 2020-2023  润新知