1. 程式人生 > >二分/模擬-51Nod 1279-扔盤子

二分/模擬-51Nod 1279-扔盤子

題目連結:1279扔盤子

題目大意:

盤子有幾種命運:1、掉到井底。2、被卡住。3、落到別的盤子上方

思路:

如果簡單的暴力會超時,對井的每一層可做優化。

如果上一層比下一層窄,那麼盤子肯定在上一層被卡,所以不妨把下一層的寬度也設為上一層的寬度,以此,井由上至下會變成一個非遞增序列,便於查詢。

二分解法:

將井“倒過來”,變成一個非遞減序列,設定一個下界,查詢盤子所能落到的最底位置,更新下界,直到盤子不能入井。

#include<iostream>
#include<algorithm>
using namespace std;

#define min(a,b) (a<b?a:b)
#define INF 1<<30
#define MAX_SIZE 50005

int Depth[MAX_SIZE];
int N,M;
int Up_Bound;

int Binary_Search(int Width)
{
    int l=Up_Bound,r=N;

    while(l<=r)
    {
        int mid=(l+r)/2;
        if(Width<=Depth[mid])
            r=mid-1;
        else
            l=mid+1;
    }

    return l<=N? Up_Bound=l+1 : 0;    //l>N放不下,返回0,否則返回新的下界
}

int main()
{
    while(cin>>N>>M)
    {
        Up_Bound=0;
        int Res=0;
        int StopFlag=0;
        int Width;
        Depth[0]=INF;
        for(int i=1;i<=N;i++)
        {
            cin>>Depth[i];
            Depth[i]=min(Depth[i],Depth[i-1]);    //預處理,取上下層窄
        }
        sort(Depth+1,Depth+N+1);//倒序

        for(int i=1;i<=M;i++)
        {
            cin>>Width;
            if(!Binary_Search(Width))//查詢盤子能到最底的位置
                StopFlag=1;

            if(StopFlag)    //井放不下,只輸入不做處理
                continue;
            Res++;
        }
        cout<<Res<<endl;
    }
    return 0;
}

純暴力:

#include<stdio.h>
#define MAX_SIZE 50005

int Depth[MAX_SIZE];
int NowMaxDepth;
int N,M,Plate;
int cnt=0;


int main()
{
    scanf("%d%d",&N,&M);
    NowMaxDepth=N;
    for(int i=1;i<=N;i++)
        scanf("%d",&Depth[i]);

    for(int i=1;i<=M;i++)
    {
        scanf("%d",&Plate);
        if(NowMaxDepth<=0)
            continue;
        int j;
        for(j=1;j<=NowMaxDepth;j++)
            if(Plate>Depth[j])
                break;
        if(j>NowMaxDepth)    //每一層寬度都大於盤,落到當前的底,-1
            NowMaxDepth-=1;
        else                //盤子被卡住,-2
            NowMaxDepth=j-2;
        if(NowMaxDepth!=-1)
            cnt++;
        //cout<<"Now: "<<NowMaxDepth<<endl;
    }
    printf("%d\n",cnt);
}