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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

CodeForces - 1454F Array Partition(线段树+二分)

發布時間:2024/4/11 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CodeForces - 1454F Array Partition(线段树+二分) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目鏈接:點擊查看

題目大意:給出一個長度為 n 的序列,現在要求求出任意一組 x , y , z,滿足下列條件:

  • x + y + z = n
  • max( 1 , x ) = min( x + 1 , x + y ) = max( x + y + 1 , n )
  • 題目分析:昨晚上用單調棧寫的寫崩了,到現在還是不知道哪里寫崩了。。太拉胯了

    因為這個題目給出的序列是需要靜態查詢最值,用 st 表或線段樹都可以快速查詢,因為感覺線段樹寫起來簡單就直接上線段樹了

    最簡單的一種思路是直接 n^2 去枚舉兩個斷點,然后查找符合條件的答案,不過這種方法即使配合上 st 表時間復雜度也是有點高,所以考慮優化

    枚舉其中的一個斷點肯定是無法避免的,我們假設枚舉的第一個斷點記為 x,此時 max( 1 , x ) 是已經確定了的,第一步先要去找到 y 的位置,使得 min( x + 1 , x + y ) == max( 1 , x ) 才行,不難看出的一個小結論是,對于一段前綴的最值來說,是具有單調性的,更具體的來說,前綴最大值隨著下標的遞增,這個值只會更大而不會減小,前綴最小值亦然,所以對于第二個斷點 y 我們可以直接二分去查找,此時我們已經確定下來了第一個斷點 x 的位置,設第一段的最大值為 mmax1,第二段的最小值為 mmin,第三段的最大值為 mmax2,此時分四種情況討論即可:

  • mmax1 < mmin:此時最小值的前綴偏大,需要擴大長度,故 l = mid + 1?
  • mmax1 > mmin:同上,r = mid - 1
  • mmax1 < mmax2:此時最大值的后綴偏大,需要減小長度,故 l = mid + 1?
  • mmax1 > mmax2:同上,r = mid - 1
  • 需要注意的是,上面二分的是斷點 y 的位置,所以想要擴大 mmin 的長度就需要將 y 右移,同理如果想要擴大 mmax2 的長度就需要將 y 左移

    代碼:
    ?

    //#pragma GCC optimize(2) //#pragma GCC optimize("Ofast","inline","-ffast-math") //#pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e6+100;struct Node {int l,r,mmin,mmax; }tree[N<<2];void build(int k,int l,int r) {tree[k].l=l;tree[k].r=r;if(l==r){scanf("%d",&tree[k].mmax);tree[k].mmin=tree[k].mmax;return;}int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);tree[k].mmax=max(tree[k<<1].mmax,tree[k<<1|1].mmax);tree[k].mmin=min(tree[k<<1].mmin,tree[k<<1|1].mmin); }int query_min(int k,int l,int r) {if(tree[k].l>r||tree[k].r<l)return inf;if(tree[k].l>=l&&tree[k].r<=r)return tree[k].mmin;return min(query_min(k<<1,l,r),query_min(k<<1|1,l,r)); }int query_max(int k,int l,int r) {if(tree[k].l>r||tree[k].r<l)return -inf;if(tree[k].l>=l&&tree[k].r<=r)return tree[k].mmax;return max(query_max(k<<1,l,r),query_max(k<<1|1,l,r)); }int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);int w;cin>>w;while(w--){int n;scanf("%d",&n);build(1,1,n);for(int x=1;x<n-1;x++)//枚舉第一個斷點x{int l=x+1,r=n-1;//二分第二個斷點y//區間分為了三段:[1,x][x+1,y][y+1,n]int mmax1=query_max(1,1,x);while(l<=r){int y=l+r>>1;int mmin=query_min(1,x+1,y);int mmax2=query_max(1,y+1,n);if(mmax1<mmin||mmax1<mmax2)l=y+1;else if(mmax1>mmin||mmax1>mmax2)r=y-1;else{puts("YES");printf("%d %d %d\n",x,y-x,n-y);goto end;}}}puts("NO");end:;}return 0; }

    ?

    超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生

    總結

    以上是生活随笔為你收集整理的CodeForces - 1454F Array Partition(线段树+二分)的全部內容,希望文章能夠幫你解決所遇到的問題。

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