1. 程式人生 > >洛谷 P3143 [USACO16OPEN]鉆石收藏家Diamond Collector 解題報告

洛谷 P3143 [USACO16OPEN]鉆石收藏家Diamond Collector 解題報告

math 時間 排序 eas 報告 sam object determine please

P3143 [USACO16OPEN]鉆石收藏家Diamond Collector

題目描述

Bessie the cow, always a fan of shiny objects, has taken up a hobby of mining diamonds in her spare time! She has collected \(N\) diamonds (\(N \leq 50,000\) of varying sizes, and she wants to arrange some of them in a pair of display cases in the barn.

Since Bessie wants the diamonds in each of the two cases to be relatively similar in size, she decides that she will not include two diamonds in the same case if their sizes differ by more than \(K\)

(two diamonds can be displayed together in the same case if their sizes differ by exactly \(K\)). Given \(K\), please help Bessie determine the maximum number of diamonds she can display in both cases together.

奶牛Bessie很喜歡閃亮亮的東西(Baling~Baling~),所以她喜歡在她的空余時間開采鉆石!她現在已經收集了N顆不同大小的鉆石(N<=50,000),現在她想在谷倉的兩個陳列架上擺放一些鉆石。

Bessie想讓這些陳列架上的鉆石保持相似的大小,所以她不會把兩個大小相差K以上的鉆石同時放在一個陳列架上(如果兩顆鉆石的大小差值為K,那麽它們可以同時放在一個陳列架上)。現在給出K,請你幫Bessie確定她最多一共可以放多少顆鉆石在這兩個陳列架上。

輸入輸出格式

輸入格式:

The first line of the input file contains \(N\) and \(K\) (\(0 \leq K \leq 1,000,000,000\)).

The next NN lines each contain an integer giving the size of one of the

diamonds. All sizes will be positive and will not exceed \(1,000,000,000\)

.

輸出格式:

Output a single positive integer, telling the maximum number of diamonds that

Bessie can showcase in total in both the cases.


方法很多而且都很神奇

我的做法是:對點排序,枚舉每個點作為左端點,二分一個區間的左端點超過它的右端點的位置。

在這個位置的右邊選擇一個最大的,在這個位置左邊選擇最大的,都可以事先維護(把區間重復和不重復分開統計)

註意預處理時也需要一些二分


Code:

#include <cstdio>
#include <algorithm>
const int N=5e4+10;
const int inf=0x3f3f3f3f;
int max(int x,int y){return x>y?x:y;}
int n,k,a[N],cntl[N],cntr[N],cntf[N],fr[N],fr2[N];
std::pair <int,int > b[N];
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        b[i].second=a[i];
        b[i].first=b[i].second-k;
    }
    std::sort(a+1,a+1+n);//原來的
    std::sort(b+1,b+1+n);//充當右端點後以左端點為關鍵字
    for(int i=1;i<=n;i++)//這個自己充當右端點可以覆蓋左邊的幾個(不考慮左端點)?
        cntf[i]=fr[i]=i;
    for(int i=1;i<=n;i++)//自己充當左端點右邊覆蓋幾個?
    {
        if(a[n]<=b[i].second+k) cntl[i]=n-cntf[i]+1;
        else cntl[i]=std::upper_bound(a+1,a+1+n,b[i].second+k)-a-1-cntf[i]+1;
    }
    for(int i=n;i;i--)//這個自己充當右端點可以覆蓋左邊的幾個(考慮左端點)?
    {
        if(a[1]>=b[i].second-k) cntr[i]=cntf[i];
        else cntr[i]=cntf[i]-(std::lower_bound(a+1,a+1+n,b[i].second-k)-a-1);
        fr2[i]=max(fr2[i+1],cntr[i]);
    }
    int ans=0;
    for(int i=1;i<=n;i++)//枚舉自己當左端點的點
    {
        if(b[i].second+k>b[n].first)
        {
            ans=max(ans,fr[n]-cntf[i]+1);
        }
        else
        {
            std::pair <int,int> d=std::make_pair(b[i].second+k,inf);
            int pos=std::upper_bound(b+1,b+1+n,d)-b;
            ans=max(ans,cntl[i]+fr2[pos]);
            ans=max(ans,fr[pos]-cntf[i]+1);
        }
    }
    printf("%d\n",ans);
    return 0;
}

2018.8.30

洛谷 P3143 [USACO16OPEN]鉆石收藏家Diamond Collector 解題報告