题目描述
所谓同花顺,就是指一些扑克牌,它们花⾊相同,并且数字连续。
现在我手里有n 张扑克牌,但它们可能并不能凑成同花顺。我现在想知道,最
少更换其中的多少张牌,我能让这n 张牌都凑成同花顺?
输入格式
第一行一个整数n,表⽰扑克牌的张数。
接下来n 行,每行两个整数ai 和bi。其中ai 表示第i 张牌的花色,bi 表示第
i 张牌的数字。
输出格式
一行一个整数,表示最少更换多少张牌可以达到目标。
样例输入 1
5
1 1
1 2
1 3
1 4
1 5
样例输出 1
0
样例输入 2
5
1 9
1 10
2 11
2 12
2 13
样例输出2
2
数据范围
对于30% 的数据,n ≤ 10。
对于60% 的数据,n ≤ 10^5,1 ≤ ai ≤ 10^5,1 ≤ bi ≤ n。
对于100% 的数据,n ≤ 10^5,1 ≤ ai, bi ≤ 10^9。
补充:
所谓“数字连续”,是指像这样:“4,5,6,7,8,9”。而形如“4,5,5,6,7,8,
9”(有重复数字)是不叫“连续”的。
输入数据中可能会有完全相同的牌。两张完全相同的牌是不应该出现在同一个
同花顺中的。
分析:
题目大意
给定n张扑克牌的花色和数字,问最少替换多少张牌,可以全部凑成同花顺?
30%
爆搜即可
60%
首先我们要进行去重(相同的牌只保留一张)
取花色出现次数最多的那种牌就可以
100%
仍然是要排序去重
枚举我们同花顺在已有的牌里面的最后一张牌
寻找可能的第一张牌
不对啊,这是O(n^2)的
寻找“可能的第一张牌”的时候,有一个小技巧
令last为当前牌的最后一张牌时,“可能的第一张牌”
如果当前牌的数值是a,last这张牌的数值是b,则显然要满足a-b+1 ≤n;
寻找“可能的第一张牌”的时候,有一个小技巧
令last为当前牌的最后一张牌时,“可能的第一张牌”
如果当前牌的数值是a,last这张牌的数值是b,则显然要满足a-b+1 ≤n;
如果我们的数值都是排好序的,随着我们“最后一张牌”的递增,“可能的第一张牌”显然是不降的
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100000+5;
struct card
{
int a,b;
bool operator <(const card& x) const {//重载小于运算符,sort函数要用到
return a==x.a? b<x.b : a<x.a;
}
bool operator ==(const card& y) const {//重载等于运算符,unique函数要用到
return (a==y.a&&b==y.b);
}
} cd[maxn];
int n,m;
int solve(int s,int t)
{
int i,j,ret=0;
for(i=j=s;i<=t;++i)
{
while(j<t&&cd[j+1].b-cd[i].b<n) ++j;
ret=max(ret,j-i+1);
}
return ret;
}
int main()
{
freopen("card.in", "r", stdin);
freopen("card.out", "w", stdout);
int i,j,ans=0;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d%d",&cd[i].a,&cd[i].b);
sort(cd+1,cd+n+1);
m=unique(cd+1,cd+n+1)-cd-1;
for(i=2,j=1;i<=m;i++)
if(cd[i].a!=cd[i-1].a) {
ans=max(ans,solve(j,i-1));
j=i;
}
ans=max(ans,solve(j,i-1));
printf("%d",n-ans);
fclose(stdin);
fclose(stdout);
return 0;
}
还有通过本题我发现了一个有趣的东西:
int i;
for(i=1;i<=6;i++)//一个有意思的小实验,for循环语句执行时只执行到6,但i到最后变成了7;
{}
cout<<i<<endl;
输出7;
推断for循环语句就等于:
i=1;
while(i<=6) i++;
cout<<i<<endl;
但是for循环与while语句不同的是:
在循环语句中for循环实际执行了6次, 而while语句执行了7次。
或者是:
或者是:
do
{
i++;
}while(i<=6);
cout<<i<<endl
这就与for循环语句相同了。