FZU Problem 2216 The Longest Straight(二分答案+树状数组)——第六届福建省大学生程序设计竞赛-重现赛

此文章可以使用目录功能哟↑(点击上方[+])

 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

2
7 11
0 6 5 3 0 10 11
8 1000
100 100 100 101 100 99 97 103

 Sample Output

5
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;
}
菜鸟成长记

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值