日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

CH - 0601 Genius ACM(倍增+归并排序)

發布時間:2024/4/11 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CH - 0601 Genius ACM(倍增+归并排序) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目鏈接:點擊查看

題目大意:

給定一個正整數M,對于任意一個整數集合S,定義“檢驗值”如下:

從集合S中取出M對數(即2*M個數,不能重復使用集合中的數,如果S中的整數不夠M對,則取到不能取為止),使得“每對數的差的平方”之和最大,這個最大值就稱為集合S的“檢驗值”

現在給定一個長度為N的數列A以及一個整數T,我們要把A分成若干段,使得每一段的“檢驗值”都不超過T,求最少要分成幾段

題目分析:因為題意比較難懂,我也不太會總結,就直接比這大藍書的題意抄上去了,然后一步一步分析一下這個題目的方向吧

首先我們可以知道,對于一個整數集合S,若要求檢驗值,我們必須將其排序一下,因為若要讓每對數的差的平方和最大,那肯定優先匹配最大值和最小值,其次匹配次大值和次小值,稍微證明一下:


對于任意組合的平方和可以表示為如下形式

前面的平方和是一定的,若我們想讓整個式子的值盡量大,那么我們就需要讓最大值的系數盡量小,那么顯然最大值與最小值匹配最合理,得證


因為題目中要找原數組中的連續區間,所以我們不妨固定左區間去找最大可能的右區間,對于整個數列求右區間肯定是滿足二分性質的,所以我們可以二分,但是在這個題目中顯然不太合適,因為可能會造成二分了整個區間后,只是讓當前的右端點向右移動了一點點,但是二分第一步就要檢驗(R-L)/2這么一大段,很顯然造成了時間上的浪費,所以我們可以考慮倍增,讓右區間一開始與左區間重合,不斷向右倍增,若滿足條件就擴大倍增指數為兩倍,不滿足的話就縮小兩倍,直到倍增指數為零,說明當前的右端點就是最優解了,大概過程是這樣的:

  • 初始化p=1(倍增指數),l=r
  • 求出[l,r+p]這段區間的“檢驗值”,若“檢驗值”<=t,則r+=p,p*=2,否則p/=2
  • 重復上一步,直到p的值變為0,此時R即為所求
  • 時間復雜度也是logn級別的,只不過多了一個小常數,因為是要先擴再縮,多了縮這么一步,然后處理每個區間是要先排序再遍歷,最終的時間復雜度為nlogn*logn,這個題目還是不太可行,因為n給到了5e5,按照上面算下來是2e8,雖然給了10秒,但感覺還是比較懸,所以我們可以在排序上優化,因為我們每次check區間的時候,前面的[l,mid]都已經排好序了,無序的只有[mid+1,r]這一段,所以我們不需要每次都nlogn的排序,只需要對無序的部分排序,然后用歸并排序的思想合并起來就好了

    這樣優化下來,就能把logn優化掉了,總時間復雜度為nlogn,雖然帶著點小常數,但無傷大雅了已經

    注意各個變量記得開longlong,然后就是通過這個題目學了一波merge函數,作用正是將兩個有序容器合并為一個有序容器,在這個題目中可以簡化操作(懶死了)

    代碼:

    #include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> #include<unordered_map> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=5e5+100;int n,m;LL a[N],temp[N],temp1[N],k;//temp[i]代表1~i的有序數組 temp1用于輔助排序bool check(int l,int mid,int r) {for(int i=mid;i<=r;i++)//將原數組的值拿下來并排序temp[i]=a[i];stable_sort(temp+mid,temp+r+1);merge(temp+l,temp+mid,temp+mid,temp+r+1,temp1+l);LL ans=0;for(int i=1;i<=min(m,(r-l+1)/2);i++)//求一下檢驗值ans+=(temp1[l+i-1]-temp1[r-i+1])*(temp1[l+i-1]-temp1[r-i+1]);if(ans<=k)//若滿足條件,返回true并將[l,r]區間更新為有序{for(int i=l;i<=r;i++)temp[i]=temp1[i];return true;}return false; }int main() { // freopen("input.txt","r",stdin); // ios::sync_with_stdio(false);int w;cin>>w;while(w--){scanf("%d%d%lld",&n,&m,&k);for(int i=1;i<=n;i++)scanf("%lld",a+i);int l=1,r=1,p=1,ans=0;temp[1]=a[1];while(r<=n){if(!p){ans++;r++;l=r;p=1;temp[l]=a[l];}else{if(r+p<=n&&check(l,r+1,r+p)){r+=p;p*=2;}elsep/=2;}}printf("%d\n",ans);}return 0; }

    ?

    總結

    以上是生活随笔為你收集整理的CH - 0601 Genius ACM(倍增+归并排序)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。