【BZOJ1071】【SCOI2007】組隊 利用單調性的雙指標

空灰冰魂發表於2015-05-15

連結:

#include <stdio.h>
int main()
{
    puts("轉載請註明出處[vmurder]謝謝");
    puts("網址:blog.csdn.net/vmurder/article/details/45746089");
}

題解:

三個定義:高度h,v速度,Ah+Bv為s
首先我們在外圈列舉來固定其中一個權值,姑且列舉v吧。每次列舉值大寫為V。
然後在內圈就可以做單調佇列了。

我們列舉讓h遞增,每次為H,然後發現原來的式子要滿足 Ah+Bv<=C+AH+BV

Ah+Bv<=C+AH+BV

然後 H增大會使得右式增大,然後如果我們按s(定義去題解第一句話找)為鍵值從小到大排序,那麼滿足此式的隊員是單調上升的。

然後 我們單調地每次把滿足此式子的隊員加入佇列,判斷如果其v值滿足條件 V<=v<=V+CB

V<=v<=V+\frac{C}{B}
,則把它計數,即此種列舉情況時的ans++。( v<=V+CB
v<=V+\frac{C}{B}
為什麼對?如果 v>V+CB
v>V+\frac{C}{B}
,則 BvBV>C
Bv-BV>C
然後你懂得)【加入環節】

然後 會有一些被計數的隊員身高式子存在 h<H

h<H
,我們從前往後單調地把身高不滿足上式的出隊,如果之前被計數了,則此種列舉情況時的ans- -。【彈出環節】

這樣比較一下這 n2

n^2
個答案,我們就在 O(n2)
O(n^2)
的時間複雜度下解決了這道題。

但是?【彈出環節】是否會彈出一些【加入環節】沒有加入的點呢?

讓我來猜一猜,你的答案一定是”不會“吧?
然而答案是會,但是這種點並不會影響答案。

分類討論下
首先如果一個點滿足被計數的條件即 V<=v<=V+CB

V<=v<=V+\frac{C}{B}
,那麼如果又滿足 h<H
h<H
那麼有 0+B(vV)<=C
0+B(v-V)<=C
,而A(hH)<0
A(h-H)則一定<0

所以 A(hH)+B(vV)<=C
A(h-H)+B(v-V)<=C
。。。。。。所以一定加進來然後被計數過,不會減多了。

然後如果不滿足被計數的條件。23333,都沒有被計數我們管它作甚?

程式碼:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 5050
using namespace std;
int n,A,B,C;
int Max,Min,l,r,cnt,ans;
struct KSD
{
    int h,v,s;
    void keep(){s=A*h+B*v;}
}x[2][N];
inline bool cmph(const KSD &a,const KSD &b){return a.h<b.h;}
inline bool cmps(const KSD &a,const KSD &b){return a.s<b.s;}
inline bool check(int id,int d)
{return x[id][d].v<=Max&&x[id][d].v>=Min;}
int main()
{
    int i,j,k;
    scanf("%d%d%d%d",&n,&A,&B,&C);
    for(i=1;i<=n;i++)
    {
        scanf("%d%d",&x[0][i].h,&x[0][i].v);
        x[0][i].keep(),x[1][i]=x[0][i];
    }
    sort(x[0]+1,x[0]+n+1,cmph);
    sort(x[1]+1,x[1]+n+1,cmps);
    for(i=1;i<=n;i++) // 列舉v最小值
    {
        Min=x[0][i].v,Max=Min+C/B;
        l=r=cnt=0;
        for(j=1;j<=n;j++) // 列舉h最小值
        {
            while(r<n&&x[1][r+1].s-A*x[0][j].h-B*x[0][i].v<=C)
                cnt+=check(1,++r);//按照s排序取出可行隊員
            while(l<n&&x[0][l+1].h<x[0][j].h)cnt-=check(0,++l);
            ans=max(ans,cnt);//再幹掉一些當初入隊時計數了的隊員
        }
    }
    printf("%d\n",ans);
    return 0;
}

相關文章