题意:有n张牌,最大为m,其中0能充当1-m的任意牌,求顺子的最大长度
思路:这道题开始我是用了一个队列维护顺子,从1到m开始枚举,如果这张牌存在的话,直接push进去,如果不存在的话,我们也push进去,但0的个数我们要减去1,如果此时0的个数为0的话,我们开始pop,直到pop出一个需要用0来代替的数。此过程队列的最大长度就是答案。
看了题解后发现二分也能做
#include <iostream>
#include <algorithm>
#include <string.h>
#include <cstdio>
#include <queue>
using namespace std;
const int maxn = 100005;
int vis[maxn];
int main(void){
int t;
scanf("%d",&t);
while(t--){
int n,m;
scanf("%d%d",&n,&m);
memset(vis,0,sizeof(vis));
int cnt0 = 0;
for(int i = 1; i <= n; i++){
int id;
scanf("%d",&id);
if(id == 0){
cnt0++;
}
else{
vis[id] = 1;
}
}
queue<int> q;
int ans = 1;
for(int i = 1; i <= m; i++){
if(vis[i]){
q.push(i);
int ll = q.size();
ans = max(ans,ll);
}
else{
if(cnt0 > 0){
q.push(i);
int ll = q.size();
ans = max(ans,ll);
cnt0--;
}
else{
while(!q.empty()){
int temp = q.front();
if(vis[temp] == 0){
cnt0++;
q.pop();
break;
}
q.pop();
}
if(cnt0 > 0){
q.push(i);
int ll = q.size();
ans = max(ans,ll);
cnt0--;
}
}
}
}
printf("%d\n",ans);
}
return 0;
}
二分做法
#include <iostream>
#include <algorithm>
#include <string.h>
#include <cstdio>
using namespace std;
const int maxn = 100005;
int vis[maxn];
int num[maxn];
int main(void){
int t;
scanf("%d",&t);
while(t--){
int n,m;
scanf("%d%d",&n,&m);
memset(vis,0,sizeof(vis));
memset(num,0,sizeof(num));
int cnt0 = 0;
for(int i = 1; i <= n; i++){
int id;
scanf("%d",&id);
if(id == 0){
cnt0++;
}
else{
vis[id] = 1;
}
}
num[0] = 0;
for(int i = 1; i <= m; i++){
num[i] = num[i - 1] + !vis[i];
}
int ans = 1;
for(int i = 0; i <= m; i++){
int l = i,r = m,mid;
while(l <= r){
mid = (l + r) / 2;
if(num[mid] - num[i] > cnt0){
r = mid - 1;
}
else{
l = mid + 1;
}
}
ans = max(ans,r - i);
}
printf("%d\n",ans);
}
return 0;
}