1. 纸牌
题目描述
在桌面上放着n张纸牌,每张纸牌有两面,每面都写着一个非负整数。你的邪王真眼可以看到所有牌朝上的一面和朝下的一面写的数字。现在你需要将一些牌翻过来,使得所有牌朝上的一面中,至少有一半(≥n/2)的数字是一样的。请你求出最少需要翻几张牌,或者判断无解。
注意:在翻牌的时候,你不能把牌扔掉,不能偷偷把别的牌放进来,也不能用笔涂改牌上面的数字。
输入格式
第一行包含一个整数n,表示牌的数量;
接下来n行,每行两个非负整数ai, bi,表示每张牌上写的两个数字,ai对应朝上的一面,bi对应朝下的一面。
输出格式
如果有解,则输出一个整数,表示最少的翻牌次数,否则输出Impossible。
样例输入1
3
1 2
2 1
3 4
样例输出1
1
样例解释1
把第一张牌翻过来,那么就有两个2一个3朝上了,2的数量超过了半数。
样例输入2
3
1 2
3 4
5 6
样例输出2
Impossible
样例解释2
所有数字都只有一个,因此相同的数字数超过半数是不可能的。
数据范围
测试点编号 | n | ai, bi |
1 | ≤10 | ≤103 |
2 | ||
3 | ≤103 | |
4 | ||
5 | ≤5*104 | ≤106 |
6 | ||
7 | ≤3*105 | |
8 | ||
9 | ≤109 | |
10 |
对所有数据,有n>0,ai, bi≥0。
对于20%,随便搜,枚举翻哪个。
对于80%,记录每个数字在正面出现的次数和在反面出现的次数,依次判断,注意有坑,就是正反一样,需要特判
对于100%,加个离散化
还有,操作次数至少是0,不能是负数,被这个坑了没a
代码:
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int maxn=300005; 5 int n,p[maxn<<1][2],Min=0x3fffffff; 6 struct gg{ 7 int val,bol,flag; 8 bool operator < (const gg &o)const{ 9 return val<o.val; 10 } 11 }e[maxn<<1]; 12 int main() 13 { 14 scanf("%d",&n); 15 for(int i=1;i<=n;i++){ 16 int x,y; 17 scanf("%d%d",&x,&y); 18 e[i*2-1].val=x; 19 e[i*2-1].bol=1; 20 e[i*2].val=y; 21 e[i*2].bol=0; 22 if(x==y)e[i*2].flag=1; 23 } 24 sort(e+1,e+2*n+1); 25 e[0].val=-1; 26 int last=0,tem2=0; 27 for(int i=1;i<=2*n;i++){ 28 if(e[i].flag)continue; 29 if(e[i].val==e[tem2].val){ 30 p[last][e[i].bol]++; 31 } 32 else { 33 p[++last][e[i].bol]++; 34 } 35 tem2=i; 36 } 37 for(int i=last;i>=1;i--){ 38 if((p[i][1]+p[i][0])*2>=n){ 39 Min=min(Min,max((n+1)/2-p[i][1],0)); 40 } 41 } 42 if(Min!=0x3fffffff)printf("%d\n",Min); 43 else printf("Impossible\n"); 44 return 0; 45 }