主頁 >  其他 > P9376 題解

P9376 題解

2023-05-31 08:19:48 其他

首先考慮怎么暴力,

考慮把每個數進行 \(B\) 進制分解,然后我們驚奇的發現這兩個操作就是把最低位去掉和往最低位后面插入一個數,

然后我們順藤摸瓜,把每個數的分解扔到 Trie 樹上,我們發現我們要找到一個節點,使得所有單詞節點到其的距離之和最短,答案就是這個最短距離,

這里直接考慮一個 Trie 樹上 dp,記所有單詞節點到節點 \(i\) 的最短距離為 \(dp_i\),然后直接去轉移,

然后考慮找找性質,

\(sz_i\) 表示以節點 \(i\) 為根的子樹內單詞節點數量,我們發現節點 \(i\) 的轉移如下 \(dp_i = dp_{fa_i} - sz_j + (sz_1 - sz_j)\)

又因為 \(sz_i \leq sz_{fa_i}\),所以只有當節點 \(i\) 滿足 \(sz_i \times 2 > sz_1\) 進入到以 \(i\) 為根的子樹轉移才最優,

而我們又發現對于一個節點滿足條件的子節點至多只有 \(1\)

也就是說如果把最優答案在樹上的轉移畫出來,并稱其為最優路徑,那么首先這一定是一條從根出發的路徑,而且以這條路徑所代表的數為前綴的數一定超過總數的一半

然后有兩種優化方向,

第一種是利用可持久化 Trie 樹預處理,然后直接在 Trie 上利用剛剛的性質暴力 \(\log_{B} V\) 查詢,缺點是對于每個 \(B\) 都要建一棵樹,

第二種是因為我們只在乎最優路徑上的轉移,所以我們隨機抽取 \(\log n\) 個節點放到 Trie 樹上,顯然因為這個性質類似于絕對眾數的性質,因此最優的轉移路徑不在 Trie 上出現的可能只有 \(\frac{1}{n}\),那么多抽取幾個節點就可以基本保證一定會出現,

那么轉移路徑找出來了,現在問題是轉移中 \(sz_i\) 怎么求?

我們有發現 \(sz_i\) 等價于 \(B\) 進制下以從根節點到節點 \(i\) 所表示的數為前綴的數的數量,而這個可以列舉這個前綴后面有幾位數轉變成一個連續區間上查詢權值為 \([L,R]\) 的數的數量,這個可以直接主席樹來搞,這么做缺點是復雜度是 \(n \log_{B}^3 V\)

考慮到 \(\log_{2} n\) 一般遠大于 \(\log_{3} n\)

所以結合兩種演算法,用第一種演算法解決 \(B = 2\) 的詢問,用第二種演算法解決其他詢問,

那么就做完了,

代碼極丑,慎入,

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int top = 100000001;
const int maxn = 1e6+114;
struct Node{
    int sz;//當前這個節點子樹內有多少個單詞節點
    vector <pair<int,int> > edge;//邊
}Trie[maxn];
struct node{
    int sz;
    int ls,rs;
}_01trie[maxn*30];
struct NODE{
    int val;
    int ls,rs;
}SGTtree[maxn*30];
int SGTroot[maxn];
int SGTtot=1;
int SGTask(int ql,int qr,int lt,int rt,int L,int R){
    if(rt<ql||lt>qr){
        return 0;
    }
    if(ql<=lt&&rt<=qr){
        return SGTtree[R].val-SGTtree[L].val;
    }
    int mid=(lt+rt)/2;
    int res=0;
    res+=SGTask(ql,qr,lt,mid,SGTtree[L].ls,SGTtree[R].ls);
    res+=SGTask(ql,qr,mid+1,rt,SGTtree[L].rs,SGTtree[R].rs);
    return res;
}
int SGTquery(int l,int r,int cl,int cr){
    return SGTask(cl,cr,1,top,SGTroot[l-1],SGTroot[r]);
}
void SGTupdate(int cur,int lst,int lt,int rt,int pos,int v){
    SGTtree[cur].val=SGTtree[lst].val+v;
    if(lt==rt){
        return ;
    }
    int mid=(lt+rt)/2;
    if(pos<=mid){
        SGTtree[cur].rs=SGTtree[lst].rs;
        SGTtree[cur].ls=++SGTtot;
        SGTupdate(SGTtree[cur].ls,SGTtree[lst].ls,lt,mid,pos,v);
    }
    else{
        SGTtree[cur].ls=SGTtree[lst].ls;
        SGTtree[cur].rs=++SGTtot;
        SGTupdate(SGTtree[cur].rs,SGTtree[lst].rs,mid+1,rt,pos,v);
    }
}
int qpow(int a,int b){
    if(b==0) return 1;
    if(b==1) return min(a,top);
    int res=min(qpow(a,b/2),top);
    res=min(top,res*res);
    if(b%2==1) res=min(res*a,top);
    return min(top,res);
}
void SGTadd(int pos,int val){
    SGTroot[pos]=++SGTtot;
    SGTupdate(SGTroot[pos],SGTroot[pos-1],1,top,val,1);
}
int SUMQUERY(int B,int L,int R){//查詢 B 進制下區間 [L,R] 所有數長度之和 
    int res=0;
    for(int k=1;k<=30;k++){
        int l=min(top,qpow(B,k-1)),r=min(top,qpow(B,k)-1);
        res+=SGTquery(L,R,l,r)*k;
        if(r==top) break;
    }
    return res;
}
int PREQUERY(int x,int B,int L,int R){//查詢 B 進制下區間 [L,R] 內多少個數前綴為 x
    int res=0;
    for(int k=0;k<=30;k++){
        int l=min(top,x*qpow(B,k)),r=min(top,(x+1)*qpow(B,k)-1);
        res+=SGTquery(L,R,l,r);
        if(r==top) break;
    }
    return res;
}
int tot=1,anser;
int _01tot=1;
int sum;
int n,m;
int flag;
stack<int> s;
int root[maxn],Sum[maxn];
void _01insert(int cur,int lst){
    _01trie[cur].sz++;
    s.pop();
    if(s.size()==0) return ;
    if(s.top()==0){
        _01trie[cur].rs=_01trie[lst].rs;
        _01trie[cur].ls=++_01tot;
        _01trie[_01trie[cur].ls].sz+=_01trie[_01trie[lst].ls].sz;
        _01insert(_01trie[cur].ls,_01trie[lst].ls);
    }
    else{
        _01trie[cur].ls=_01trie[lst].ls;
        _01trie[cur].rs=++_01tot;
        _01trie[_01trie[cur].rs].sz+=_01trie[_01trie[lst].rs].sz;
        _01insert(_01trie[cur].rs,_01trie[lst].rs);
    }
}
void _01dfs(int l,int r,int ans,int L,int R){
    if(l==0&&r==0) return ;
    anser=min(anser,ans);
    if(_01trie[_01trie[r].ls].sz-_01trie[_01trie[l].ls].sz>_01trie[_01trie[r].rs].sz-_01trie[_01trie[l].rs].sz){
        _01dfs(_01trie[l].ls,_01trie[r].ls,ans-(_01trie[_01trie[r].ls].sz-_01trie[_01trie[l].ls].sz)+(_01trie[R].sz-_01trie[L].sz-(_01trie[_01trie[r].ls].sz-_01trie[_01trie[l].ls].sz)),L,R);
    }
    else{
        _01dfs(_01trie[l].rs,_01trie[r].rs,ans-(_01trie[_01trie[r].rs].sz-_01trie[_01trie[l].rs].sz)+(_01trie[R].sz-_01trie[L].sz-(_01trie[_01trie[r].rs].sz-_01trie[_01trie[l].rs].sz)),L,R);
    }
}
int _01query(int l,int r){
    anser=INT_MAX;
    _01dfs(root[l-1],root[r],Sum[r]-Sum[l-1],root[l-1],root[r]);
    return anser;
}
void _01add(int x,int B,int pos){
    while(x!=0){
        s.push(x%B);
        x/=B;
    }
    s.push(0);
    Sum[pos]=s.size()-1+Sum[pos-1];
    root[pos]=++_01tot;
    _01trie[root[pos]].sz+=_01trie[root[pos-1]].sz;
    _01insert(root[pos],root[pos-1]);
}
void insert(int cur,int val){
    Trie[cur].sz+=val;
    s.pop();
    if(s.size()==0) return ;
    for(pair<int,int> v:Trie[cur].edge){
        if(v.second==s.top()){
            insert(v.first,val);
            return ;
        }
    }
    Trie[cur].edge.push_back(make_pair(++tot,s.top()));
    insert(tot,val);
}
void add(int x,int B){
    while(x!=0){
        s.push(x%B);
        x/=B;
    }
    s.push(0);
    sum+=s.size()-1;
    insert(1,1);
}
void dfs(int cur,int ans,int PRE,int S,int B,int L,int R){
    anser=min(anser,ans);
    for(pair<int,int> v:Trie[cur].edge){
        int nxt=PRE*B+v.second;
        int g=PREQUERY(nxt,B,L,R);
        if((S-g)-g>=0) continue;
        dfs(v.first,ans-g+(S-g),nxt,S,B,L,R);
    }
}
int query(int B,int L,int R){
    anser=INT_MAX;
    dfs(1,SUMQUERY(B,L,R),0,(R-L+1),B,L,R);
    return anser;
}
void clear(){
    for(int i=1;i<=tot;i++){
        Trie[i].edge.clear();
        Trie[i].sz=0;
    }
    sum=0;
    tot=1;
}
int a[maxn];
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++){
            cin>>a[i];
            SGTadd(i,a[i]);
            _01add(a[i],2,i);
    }       
    while(m--){
        int l,r,B;
        cin>>l>>r>>B;
        if(B==2){
            cout<<_01query(l,r)<<"\n";
        }
        else{
        clear();
        for(int j=1;j<=22;j++){
            int x=rand()%(r-l+1)+l;
            add(a[x],B);
        }
        cout<<query(B,l,r)<<'\n';
        }
    }            
}
/*
5 2
7 6 5 8 9
1 3 2
2 5 2
*/

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/553848.html

標籤:其他

上一篇:AtCoder Beginner Contest 303

下一篇:返回列表

標籤雲
其他(160012) Python(38189) JavaScript(25464) Java(18161) C(15234) 區塊鏈(8268) C#(7972) AI(7469) 爪哇(7425) MySQL(7217) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5873) 数组(5741) R(5409) Linux(5344) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4579) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2434) ASP.NET(2403) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1977) 功能(1967) Web開發(1951) HtmlCss(1950) C++(1927) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1878) .NETCore(1862) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • P9376 題解

    首先考慮怎么暴力。 考慮把每個數進行 $B$ 進制分解,然后我們驚奇的發現這兩個操作就是把最低位去掉和往最低位后面插入一個數。 然后我們順藤摸瓜,把每個數的分解扔到 Trie 樹上,我們發現我們要找到一個節點,使得所有單詞節點到其的距離之和最短,答案就是這個最短距離。 這里直接考慮一個 Trie 樹 ......

    uj5u.com 2023-05-31 08:19:48 more
  • AtCoder Beginner Contest 303

    ## [A - Similar String (abc303 a)](https://atcoder.jp/contests/abc303/tasks/abc303_a) ### 題目大意 給定兩個字串,問這兩個字串是否相似。 兩個字串相似,需要每個字母,要么完全相同,要么一個是`1`一個是` ......

    uj5u.com 2023-05-31 08:19:43 more
  • 牛客小白月賽73

    # A.最小的數字 ### 題目: ![](https://img2023.cnblogs.com/blog/2960080/202305/2960080-20230526220648535-777334559.png) ### 分析: 簡單列舉一下,找到第一個大于等于n的且是3的倍數的數 ### ......

    uj5u.com 2023-05-31 08:19:25 more
  • 基于ZigBee3.0技術的數傳電臺功能使用詳解

    一、ZigBee3.0數傳電臺功能簡介 1、4G DTU數傳電臺LINK燈詳解 基于zigbee3.0通信技術的4G DTU數傳電臺LINK燈用于指示模塊當前網路狀態,設備入網成功后LINK燈常亮,當設備沒有網路時LINK燈熄滅;在協調器模式下,該引腳指示zigbee模塊是否正常建立網路,協調器和路 ......

    uj5u.com 2023-05-31 08:18:54 more
  • 提高生產力的最佳免費開源終端:WindTerm

    WindTerm是一個免費的開源終端工具,旨在提高開發人員和系統管理員的生產力。它為使用命令列的用戶帶來了更好的終端體驗,使其能夠更快速、高效地完成操作。

    相比傳統終端,WindTerm具有多個優勢,如支持多標簽頁、自定義主題、自動補全等功能,這些功能都可以顯著提高開發人員的作業效率。此外,Win... ......

    uj5u.com 2023-05-31 08:18:39 more
  • Three.js教程:物件克隆、復制

    推薦:將NSDT場景編輯器加入你的3D工具鏈 其他系列工具:NSDT簡石數字孿生 物件克隆.clone()和復制.copy() Threejs大多數物件都有克隆.clone()和復制.copy()兩個方法,點模型Points、線模型Line、網格網格模型Mesh一樣具有這兩個方法。 復制方法.cop ......

    uj5u.com 2023-05-31 08:18:06 more
  • Java 集合類詳解(一)

    ## 為什么要使用集合 存盤多個資料可以使用陣列,但由于陣列在記憶體中是連續存盤的,所以會有一些限制。比如陣列在創建時就要指定長度,即可以容納的元素個數,且指定后無法更改;陣列在創建時需要指定元素的型別,并且所有元素都必須是該型別或其子類;添加或洗掉陣列中的元素需要創建一個新陣列再進行元素復制,比較麻 ......

    uj5u.com 2023-05-31 08:17:43 more
  • 詳解RocketMQ 順序消費機制

    摘要:順序訊息是指對于一個指定的 Topic ,訊息嚴格按照先進先出(FIFO)的原則進行訊息發布和消費,即先發布的訊息先消費,后發布的訊息后消費。 本文分享自華為云社區《RocketMQ 順序消費機制》,作者: 勇哥java實戰分享 。 順序訊息是指對于一個指定的 Topic ,訊息嚴格按照先進先 ......

    uj5u.com 2023-05-31 08:17:16 more
  • 直播原始碼平臺搭建技術分享之直播短信功能

    在利用直播原始碼去開發平臺中,直播原始碼功能技術是開發直播平臺的重要技術之一,今天我就為大家分享直播原始碼平臺搭建技術分享直播短信功能實作。 ......

    uj5u.com 2023-05-31 08:16:52 more
  • 5年測驗工程師經歷,下一步轉開發還是繼續測驗?

    測驗五年,沒有積累編程腳本能力和自動化經驗,找作業時都要求語言能力,自動化框架。
    感覺開發同事積累的經歷容易找作業。
    下一步,想辦法轉開發崗還是繼續測驗???
    正常情況下,有了四年的測驗工程師經歷,應該可以達到中級測驗工程師的水平了。作為一個初中級測驗工程師下一步是轉開發還是繼續做測驗,個人建議是做... ......

    uj5u.com 2023-05-31 08:16:12 more