此文章可以使用目录功能哟↑(点击上方[+])
FZU Problem 2216 The Longest Straight
Accept: 0 Submit: 0
Time Limit: 1000 mSec Memory Limit : 32768 KB
Problem Description
ZB is playing a card game where the goal is to make straights. Each card in the deck has a number between 1 and M(including 1 and M). A straight is a sequence of cards with consecutive values. Values do not wrap around, so 1 does not come after M. In addition to regular cards, the deck also contains jokers. Each joker can be used as any valid number (between 1 and M, including 1 and M).
You will be given N integers card[1] .. card[n] referring to the cards in your hand. Jokers are represented by zeros, and other cards are represented by their values. ZB wants to know the number of cards in the longest straight that can be formed using one or more cards from his hand.
Input
The first line contains an integer T, meaning the number of the cases.
For each test case:
The first line there are two integers N and M in the first line (1 <= N, M <= 100000), and the second line contains N integers card[i] (0 <= card[i] <= M).
Output
For each test case, output a single integer in a line -- the longest straight ZB can get.
Sample Input
7 11
0 6 5 3 0 10 11
8 1000
100 100 100 101 100 99 97 103
Sample Output
3
Hint
Problem Idea
解题思路:
【题意】
纸牌游戏
手上有n张牌,每张牌的大小card[i]∈[1,m]
这n张牌中可能存在jokers(这张牌可以充当任何点数的牌来使用),用card[i]=0来区分
问这n张牌能够组成最长连续点数串的串长为多少
例如样例1
7张牌,大小分别为0 6 5 3 0 10 11,可见有两张jokers,分别充当点数为2,4的牌,这样最长连续点数串为2 3 4 5 6,故串长为5
【类型】
二分答案+树状数组
【分析】
考虑到此题未知量有点多
所以本人采取了二分答案的方法
即二分最长连续点数串的串长,再判断是否存在此串长条件下的解即可
因为连续点数串只要连续的点数,所以相同点数的牌保留1张就够了,多了也没什么用
然后,我们来讲解一下求解过程
先是二分最长连续点数串的串长,记为len
然后遍历以点数为i(i∈[1,m+1-len])的牌作为最长连续点数串串首的牌
用树状数组求出串中没有对应点数的牌有多少张,与jokers的数量作比较
如果jokers的数量要多,显然可以用jokers来替代没有的点数
直到二分出最长的串长即可
【时间复杂度&&优化】
O(nlogn)
题目链接→FZU Problem 2216 The Longest Straight
Source Code
/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define PI acos(-1.0)
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 100005;
const int M = 5005;
const int inf = 1000000007;
const int mod = 1000003;
int c[N],p,m;
bool v[N];
int lowbit(int t)
{//计算c[t]展开的项数
return t&(-t);
}
void update(int i,int x)
{
while(i<=m)
{
c[i]=c[i]+x;
i+=lowbit(i);
}
}
int Sum(int n) //求前n项的和.
{
int sum=0;
while(n>0)
{
sum+=c[n];
n-=lowbit(n);
}
return sum;
}
bool judge(int len)
{
for(int i=1;i+len-1<=m;i++)
if(Sum(i+len-1)-Sum(i-1)+p>=len)
return true;
return false;
}
int main()
{
int t,n,i,card,l,r,mid,ans;
scanf("%d",&t);
while(t--)
{
p=0;
memset(c,0,sizeof(c));
memset(v,false,sizeof(v));
scanf("%d%d",&n,&m);
for(i=0;i<n;i++)
{
scanf("%d",&card);
v[card]=true;
if(!card)
p++;
}
for(i=1;i<=m;i++)
if(v[i])
update(i,1);
l=1;r=min(n,m);
while(l<=r)
{
mid=(l+r)/2;
if(judge(mid))
l=mid+1,ans=mid;
else
r=mid-1;
}
printf("%d\n",ans);
}
return 0;
}
菜鸟成长记