倍增

  • 天才ACM

原題鏈接

給定一個整數(shù)M夜畴,對于任意一個整數(shù)集合S辆布,定義“校驗值”如下:

從集合S中取出M對數(shù)(即2*M個數(shù)翠肘,不能重復(fù)使用集合中的數(shù)脊串,如果S中的整數(shù)不夠M對,則取到不能取為止)涎永,使得“每對數(shù)的差的平方”之和的最大涯保,這個最大值就成為集合S的“校驗值”

現(xiàn)在給定一個長度為N的數(shù)列A以及一個整數(shù)T。我們要把A分成若干段钞诡,使得每一段“校驗值”都不超過T郑现。求最少需要分成幾段?

即當(dāng)確定一個左端點L之后荧降,右端點R在A[L]~A[R]的校驗值不超過T的前提下接箫,最大能取到多少


倍增主要用于解決二分的缺點:如果每次詢問給定的整數(shù)T都非常小,造成答案k也非常小朵诫,那么該算法可能還不如從前向枚舉更優(yōu)


因此對于這道題:

1.初始化p=1,R=L=0辛友。

2.求出[L,R+p]這一段區(qū)間的“校驗值”,若“校驗值<=T”,則R+=p,p*=2剪返;否則p/=2

3.重復(fù)上一步废累,直到p的值變?yōu)?,此時R即為所求

 int start=0,end=0;
        while(end<n)
        {
            int len=1;
            while(len)
            {
                if(end+len<=n&&check(start,end+len))//(范圍成立)&&(cheeck)
                {
                    end+=len;//更新起點
                    len<<=1;//更新擴(kuò)大步伐
                }
                else 
                    len>>=1;//縮小步伐
                
            }
            start=end;//前一部分已經(jīng)完成随夸,下一段起點從終點開始
        }

時間復(fù)雜度:

以上過程最多循環(huán)O(logN)次九默,每次循環(huán)對長度為O(R-L)的一段進(jìn)行排序,完成整個題目的求解累計擴(kuò)展長度為N宾毒,因次總體時間復(fù)雜度為O(NlogN*logN)

優(yōu)化:

在處理 [start,end)[start,end) 的時候驼修,已經(jīng)將 [start,end)[start,end) 排好序了殿遂,所以不需要在處理 [start,end+len)[start,end+len) 時再排序。

處理 [start,end+len)[start,end+len) 時乙各,只需要將 [end,end+len)[end,end+len) 排序墨礁,然后將 [start,end)[start,end) 與 [end,end+len)[end,end+len) 這兩段區(qū)間進(jìn)行歸并即可。

假設(shè)一共將數(shù)組劃分成了 kk 個區(qū)間(這里的區(qū)間指的是每次二分里面check的區(qū)間總和耳峦,并非題目中所指的區(qū)間)恩静,每個區(qū)間的長度分別為 len1,len2,?,lenklen1,len2,?,lenk。

那么按上述方法只需要將每個區(qū)間排序一遍蹲坷,所以時間復(fù)雜度為 O(len1loglen1+len2loglen2+..+lenkloglenk)≤O(nlogn)
加上每次歸并的時間復(fù)雜度為O(n)驶乾,總的時間復(fù)雜度為 O(n+nlogn)=O(nlogn)


收獲一個精煉板塊

 for(int i=0;i<k&&i<m;i++,k--)
     sum+=sq(t[i]-t[k-1]);
//從最前(0)與最后(k-1)分別開始取最多m對,雙指針取數(shù)
    

  • 解法一: 倍增O(NlogN*logN)

#include<iostream>
#include<algorithm>

using namespace std;

typedef long long ll;

const int N=500005;

int num,n,m;
ll T;

ll a[N],t[N],temp[N];

ll sq(ll x)
{
    return x*x;
}

bool check(ll l,ll r)
{
    int k=0;
    for(int i=l;i<r;i++)
        t[k++]=a[i];
    sort(t,t+k);
    ll sum=0;
    for(int i=0;i<k&&i<m;i++,k--)//最多取m對,雙指針取數(shù)
        sum+=sq(t[i]-t[k-1]);
    return sum<=T;
}

int main()
{
    scanf("%d",&num);
    while(num--)
    {
        scanf("%d%d%lld",&n,&m,&T);
        for(int i=0;i<n;i++)
            scanf("%lld",&a[i]);
        int ans=0;
        ll start=0,end=0;
        while(end<n)
        {
            ll len=1;
            while(len)
            {
                if(end+len<=n&&check(start,end+len))//end從0開始可以取等號
                {
                    end+=len;
                    len<<=1;
                }
                else 
                    len>>=1;
                
            }
            start=end;
            ans++;
        }
        printf("%d\n",ans);
    }
    
    return 0;
}
  • 解法二:倍增+歸并(NlogN)

#include<iostream>
#include<algorithm>

using namespace std;

typedef long long ll;

const int N=500005;

ll a[N],t[N],temp[N];
ll num,n,m,T,ans;

ll sq(ll a)
{
    return a*a;
}

bool check(ll l,ll mid,ll r)
{
    for(int i=mid;i<r;i++)//復(fù)制數(shù)組,check嘗試可不可以循签,可能不可以的話级乐,就要重來,所以必須備份
        t[i]=a[i];
    sort(t+mid,t+r);
    ll i=l,j=mid,k=0;
    while(i<mid&&j<r)
    {
        if(t[i]<t[j])
            temp[k++]=t[i++];
        else
            temp[k++]=t[j++];
    }
    while(i<mid)temp[k++]=t[i++];
    while(j<r)temp[k++]=t[j++];
    
    
   //計算校驗值
   ll sum=0;
   for(int i=0;i<m&&i<k;i++,k--)
        sum+=sq(temp[i]-temp[k-1]);
    return sum<=T;
}

int main()
{
    scanf("%lld",&num);
    while(num--)
    {
        scanf("%lld%lld%lld",&n,&m,&T);
        for(int i=0;i<n;i++)
            scanf("%lld",&a[i]);
        ans=0;
        ll len,start=0,end=0;
        while(end<n)
        {
            len=1;
            while(len)
            {
                if(end+len<=n&&check(start,end,end+len))// 如果 w 的 [start, end + len) 區(qū)間合法
                {
                    end+=len,len<<=1;
                    if(end>=n)
                        break;
                    for(ll i=start;i<end;i++)//temp里存的是從0開始的歸并序列县匠,所以要減去start
                        t[i]=temp[i-start];
                }
                else
                    len>>=1;
            }
            start=end;
            ans++;
        }
        printf("%lld\n",ans);
    }
    
    return 0;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末风科,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子乞旦,更是在濱河造成了極大的恐慌贼穆,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件兰粉,死亡現(xiàn)場離奇詭異故痊,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)亲桦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進(jìn)店門崖蜜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人客峭,你說我怎么就攤上這事豫领。” “怎么了舔琅?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵等恐,是天一觀的道長。 經(jīng)常有香客問我备蚓,道長课蔬,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任郊尝,我火速辦了婚禮二跋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘流昏。我一直安慰自己扎即,他們只是感情好吞获,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著谚鄙,像睡著了一般各拷。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上闷营,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天烤黍,我揣著相機(jī)與錄音,去河邊找鬼傻盟。 笑死速蕊,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的莫杈。 我是一名探鬼主播互例,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼筝闹!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起腥光,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤关顷,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后武福,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體议双,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年捉片,在試婚紗的時候發(fā)現(xiàn)自己被綠了平痰。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡伍纫,死狀恐怖宗雇,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情莹规,我是刑警寧澤赔蒲,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站良漱,受9級特大地震影響舞虱,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜母市,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一矾兜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧患久,春花似錦椅寺、人聲如沸浑槽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽括荡。三九已至,卻和暖如春溉旋,著一層夾襖步出監(jiān)牢的瞬間畸冲,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工观腊, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留邑闲,地道東北人。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓梧油,卻偏偏與公主長得像苫耸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子儡陨,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容