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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > windows >内容正文

windows

洛谷 P9683 A Certain Forbidden Index 题解

發(fā)布時(shí)間:2024/1/21 windows 39 coder
生活随笔 收集整理的這篇文章主要介紹了 洛谷 P9683 A Certain Forbidden Index 题解 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

題目鏈接:\(\color{Purple}\texttt{P9683 A Certain Forbidden Index}\)

填坑。提供一個(gè)相對(duì)好寫的做法。

考慮把一堆不交的區(qū)間綁在一起問(即先詢問這些區(qū)間的并,判斷答案是否在里面):對(duì)于一個(gè)區(qū)間,能與它綁在一起的區(qū)間最多只有 \(1\) 個(gè)是與它同一層的。

于是我們想到一個(gè)比較原始的做法:因?yàn)?\([1,2^k]\) 沒有任何區(qū)間可以合并,所以放最后作為單獨(dú)一塊問;從線段樹的頂端按照 BFS 序往下詢問,如果該區(qū)間 \([l,r]\) 沒有進(jìn)行過標(biāo)記(記這種區(qū)間為“初始區(qū)間”),按以下方式處理:標(biāo)記它,如果它是作為左兒子被問到的(反之同理),那么就不斷往右找下一層且它們的并集是一個(gè)區(qū)間的區(qū)間 \([l_1,r_1]\)(即滿足 \(l_1=r+1\)),然后 \([l,r]\leftarrow[l_1,r_1]\),對(duì) \([l_1,r_1]\) 進(jìn)行標(biāo)記;這樣能獲得不少的塊并且答案已經(jīng)很優(yōu)。加上對(duì) \(k=1\) 的特判可以做到 \(63\mathrm{pts}\):筆者考場(chǎng)上使用的是該做法,已經(jīng)得到了一個(gè)非常可觀的分?jǐn)?shù)。

注:對(duì)于這種做法,如果對(duì)塊內(nèi)相鄰元素連邊,在整棵線段樹上這些邊就可以構(gòu)成很多交叉的 X 型(讀者可以自行理解一下)。

但是此時(shí)答案還不是最優(yōu)的。考慮是否可以合并一些區(qū)間:我們觀察到,對(duì)于一些左 / 右端點(diǎn)在正中間的作為右 / 左兒子進(jìn)行處理的區(qū)間,是可以將它所在的塊和同一層那個(gè)唯一可以合并的區(qū)間所在的塊合并的。例如,\(k=4\) 時(shí),區(qū)間 \([7,8]\) 與區(qū)間 \([9,10]\) 所在的塊可以合并。處理的過程中考慮一下這種情況。

事實(shí)上我們可以觀察到,對(duì)于合并同一層的這種情況,我們只需處理 \([l,r]\) 滿足 \(r<2^k\)作為右兒子詢問到的“初始區(qū)間”所在的塊和它右邊那個(gè)同層的且可合并的區(qū)間所在的塊即可。證明顯然。

詢問塊內(nèi)元素的過程可以不用像其他題解一樣用二分,因?yàn)槲覀冇^察到如果一個(gè)塊的大小如果不超過 \(2\),那么二分跟樸素做法的沒有區(qū)別——實(shí)際上塊越小兩種做法的區(qū)別越小。又因?yàn)槭前凑?BFS 序從上往下問,感性理解一下就可以得知越往下問塊越小而且數(shù)量越多。實(shí)測(cè)可以獲得 \(100\mathrm{pts}\)

如果不放心可以把所有塊全部預(yù)處理出來然后按照塊的大小降序排序詢問。但是這個(gè)做法會(huì)在 \(k=14\) 的時(shí)候超時(shí),所以選用前者。

示例代碼(\(100\mathrm{pts}\)):

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
int query(int,int);
pii solve(int k){
  vector<tuple<int,int,int,int> > q;
  function<void(int,int,int)> dfs=[&](int l,int r,int w){
    if(l==r)return;
    q.emplace_back(l,l+r>>1,w-1,0);
    q.emplace_back(l+r+1>>1,r,w-1,1);
    dfs(l,l+r>>1,w-1);
    dfs(l+r+1>>1,r,w-1);
  }; // 按照 BFS 序處理出所有區(qū)間遍歷順序,0/1 表示左 / 右兒子
  dfs(1,1<<k,k);
  set<pii> t; t.emplace(1,1<<k);
  vector<tuple<vector<pii>,int,int,int,int> > s;
  for(auto [l,r,w,b]:q){
    if(t.find(make_pair(l,r))==t.end()){
      vector<pii> v; int p=(b?l:r);
      for(int i=w-1;i>=0;i--){
        v.emplace_back(b?p-(1<<i):p+1,b?p-1:p+(1<<i));
        b?p-=(1<<i):p+=(1<<i);
      } // 處理塊
      if(b){
        bool b2=false;
        if(r<(1<<k)){
          b2=true,p=r;
          for(int i=w;i>=0;i--){
            v.emplace_back(p+1,p+(1<<i));
            p+=(1<<i);
          }
        } // 可以與同一層的合并
        if(query(l-(1<<w)+1,b2?(r<<1)-l+(1<<w):r)){
          // 詢問是否在整個(gè)區(qū)間,下同
          for(auto [l1,r1]:v)
            if(query(l1,r1))return make_pair(l1,r1);
          // 詢問單個(gè)區(qū)間,下同
          return make_pair(l,r);
          // 不在上述區(qū)間就是最后一個(gè),下同
        }
      }
      else if(query(l,r+(1<<w)-1)){
        for(auto [l1,r1]:v)
          if(query(l1,r1))return make_pair(l1,r1);
        return make_pair(l,r);
      }
      for(auto [l1,r1]:v)t.emplace(l1,r1);
      t.emplace(l,r); // 使用 std::set 打標(biāo)記
    }
  }
  return make_pair(1,1<<k); // 都不是上述區(qū)間
}

總結(jié)

以上是生活随笔為你收集整理的洛谷 P9683 A Certain Forbidden Index 题解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。