思路:
洛谷的题目标签貌似不能相信了,明明是模拟他却非打上搜索的标签。看到题目一读题,马上就想到应该排序,隐隐约约感觉应该先按照花色从小到大排序再在每一种花色里按牌的大小排序。题目想让我们抽出最少的牌构成同花顺,那我们从另一个方面思考,是不是可以找最长上升子序列,那么n-序列长度就是抽出的牌了。当然,我们在排序的时候需要去重。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
struct haha {
int a, b;
}poke1[100010], poke2[100010]; //poke1是原始数据,poke2则记录poke1排序并去重后的数据
int n, cnt, tmp, ans;
bool cmp( haha x, haha y ) {
if( x.a != y.a )
return x.a < y.a; //不同花色按花色编号从小到大
if( x.a == y.a )
return x.b < y.b; //同一种花色按牌面从小到大
}
inline int read() { //读入优化
char q;
int save = 0, w = 1;
while( q < '0' || q > '9' ) {
if( q == '-' )
w = -1;
q = getchar();
}
while( q >= '0' && q <= '9' )
save = save * 10 + q - '0', q = getchar();
return w * save;
}
int main() {
n = read();
for( int i = 1; i <= n; i++ )
poke1[i].a = read(), poke1[i].b = read();
sort( poke1 + 1, poke1 + n + 1, cmp );
for( int i = 1; i <= n; i++ )
if( poke1[i - 1].a != poke1[i].a || poke1[i - 1].b != poke1[i].b ) //如果前后两副牌花色不同,或牌面不同,就符合要求
poke2[++cnt] = poke1[i];
for( int i = 1; i <= cnt; i++ ) { //枚举右端点
tmp = 0; //用来存序列长度,每更新一次右端点,这个计数器都要改为0
for( int j = i; j >= 1; j-- ) //枚举左端点
if( poke2[j].a == poke2[i].a && poke2[i].b - poke2[j].b <= n )
tmp++;
else break; //碰到不能放入序列的,说明序列到头了,退出循环,不然超时
ans = max( ans, tmp );
}
printf( "%d", n - ans );
return 0;
}