CE17.【C++ Cont】練習題組17(堆專題)

目錄

1.P2085 最小函數值?

題目

分析

方法1:暴力求解

方法2:二次函數的性質(推薦!)

代碼

提交結果

2.P1631 序列合并

分析

方法1:建兩個堆

第一版代碼

提交結果

第二版代碼

提交結果

第三版代碼

提交結果

方法2:只建一個堆

代碼

提交結果


1.P2085 最小函數值?

題目

https://www.luogu.com.cn/problem/P2085

分析

從題目的"輸出將這 n 個函數所有可以生成的函數值排序后的前 m 個元素"可以看出是堆排序的TopK問題

方法1:暴力求解

求出所有函數中的m個值,然后取前m個,n個函數各有m個值,時間復雜度過高,為O(m\cdot n),不建議使用

方法2:二次函數的性質(推薦!)

以測試用例分析畫表:

會發現:x==4及之后x的值,均是x^2+7x+1最小,只有它的函數值需要入隊

原因:x^2+7x+1的最高次的系數為1,階位最高比4x^2+5x+33x^2+4x+5都要小,同是二次函數,二次項前的系數決定階位的高低,因此有:

\lim_{x \to+ \infty} {4x^2+5x+3}>\lim_{x \to+ \infty} {3x^2+4x+5}>\lim_{x \to+ \infty} {x^2+7x+1}

從圖像上也可以看出:

算法:首先將x==1的所有函數值計算出來,然后入堆,然后每次拿出最小的那個函數值來打印,把對應的之后刪除堆頂元素,把對應的下一個函數值f(x+1)入堆

因為每次拿出最小的那個函數值,所以建立小根堆

因為要將對應的下一個函數值入堆,所以需要知道是哪個函數算的,因此要記錄函數的編號,要算f(x+1),需要知道x,因此入堆的元素是結構體,建小根堆需要運算符重載

struct node
{ull f_x;//f(x)函數值 ull num;//函數的編號 ull x;bool operator<(const node& _node) const{return f_x>_node.f_x;//建立小根堆 }		
};

?例如

設f(x)=4x^2+5x+3,編號為1;g(x)=3x^2+4x+5,編號為2;h(x)=x^2+7x+1,編號為3;先將{12,1,1}、{12,2,1}、{9,3,1}入堆,發現函數值9最小,因此刪除堆頂元素后將{h(1+1),3,2}入堆,以此類推......

注意:刪除堆頂元素只能進行m次

代碼

#include <iostream>
#include <queue>
#define endl "\n"  
using namespace std;
typedef unsigned long long ull;
const int N=1e5+10;
struct node
{ull f_x;//f(x)函數值 ull num;//函數的編號 ull x;bool operator<(const node& _node) const{return f_x>_node.f_x;//建立小根堆 }		
};
priority_queue<node> q;
ull A[N],B[N],C[N]; 
int main()
{ios::sync_with_stdio(false);cin.tie(0);ull n,m;cin>>n>>m;for (ull i=1;i<=n;i++)cin>>A[i]>>B[i]>>C[i];for (ull j=1;j<=n;j++)q.push({A[j]+B[j]+C[j],j,1});//x=1的所有函數值入隊while(m--) {node tmp=q.top();cout<<q.top().f_x<<" ";q.pop();q.push({A[tmp.num]*(tmp.x+1)*(tmp.x+1)+B[tmp.num]*(tmp.x+1)+C[tmp.num],tmp.num,tmp.x+1});} return 0;
}

提交結果

2.P1631 序列合并

fhttps://www.luogu.com.cn/problem/P1631

分析

線索"從小到大表示這 N 個最小的和",顯然屬于TopK問題

方法1:建兩個堆

由于是從小到大,應該建大根堆,將a[i]+b[j]的結果存入其中,保持大根堆內含N個元素,如果直接打印其堆頂元素的話結果是從大到小的,可以再建一個小根堆,將大根堆的堆頂元素存入小根堆,最后再打印大根堆的堆頂元素

第一版代碼

#include <iostream>
#include <queue>
using namespace std;
const int N1=1e6+10;
const int N2=1e3+10;
typedef unsigned long long ull;
ull n,a[N1],b[N1],c[N2],d[N1],s;
priority_queue<ull,vector<ull>,less<ull>> tmp_heap;
priority_queue<ull,vector<ull>,greater<ull>> result_heap;
int main()
{cin>>n;for (int i=0;i<n;i++){cin>>a[i];}for (int i=0;i<n;i++){cin>>b[i];}for (int i=0;i<n;i++){for (int j=0;j<n;j++){c[s]=a[i]+b[j];if (tmp_heap.size()<n)		{tmp_heap.push(c[s]);	} else if (tmp_heap.top()>c[s]){tmp_heap.pop();tmp_heap.push(c[s]);}s++;}}	while (tmp_heap.size()){result_heap.push(tmp_heap.top());tmp_heap.pop();		} while(result_heap.size()){cout<<result_heap.top()<<" ";result_heap.pop();}return 0;
}
提交結果

超出內存的限制,其實不用創建c[N]數組,直接使用臨時變量存儲a[i]+b[j]的結果,節約空間

第二版代碼

#include <iostream>
#include <queue>
using namespace std;
const int N1=1e6+10;
const int N2=1e3+10;
typedef unsigned long long ull;
ull n,a[N1],b[N1],d[N1],c;
priority_queue<ull,vector<ull>,less<ull>> tmp_heap;
priority_queue<ull,vector<ull>,greater<ull>> result_heap;
int main()
{cin>>n;for (int i=0;i<n;i++){cin>>a[i];}for (int i=0;i<n;i++){cin>>b[i];}for (int i=0;i<n;i++){for (int j=0;j<n;j++){c=a[i]+b[j];if (tmp_heap.size()<n)		{tmp_heap.push(c);	} else if (tmp_heap.top()>c){tmp_heap.pop();tmp_heap.push(c);}}}	while (tmp_heap.size()){result_heap.push(tmp_heap.top());tmp_heap.pop();		} while(result_heap.size()){cout<<result_heap.top()<<" ";result_heap.pop();}return 0;
}
提交結果

解決方法:有超時,說明for循環的次數過多,注意到題目的"單調不降序列",應盡量減少循環次數,觀察發現,設外循環為變量i,內循環為變量j,當i不變時,隨著j的增大a[i]+b[j]的值也在增大或者不變,當a[i]+b[j]在增大時,必定存在某個狀態有tmp_heap.top()<c,不用入堆,應該立刻退出內循環,減少循環次數?

第三版代碼

#include <iostream>
#include <queue>
using namespace std;
const int N1=1e6+10;
const int N2=1e3+10;
typedef unsigned long long ull;
ull n,a[N1],b[N1],d[N1],c;
priority_queue<ull,vector<ull>,less<ull>> tmp_heap;
priority_queue<ull,vector<ull>,greater<ull>> result_heap;
int main()
{cin>>n;for (int i=0;i<n;i++){cin>>a[i];}for (int i=0;i<n;i++){cin>>b[i];}for (int i=0;i<n;i++){for (int j=0;j<n;j++){c=a[i]+b[j];if (tmp_heap.size()<n)		{tmp_heap.push(c);	} else if (tmp_heap.top()>c){tmp_heap.pop();tmp_heap.push(c);}if (tmp_heap.top()<c)break;		}}	while (tmp_heap.size()){result_heap.push(tmp_heap.top());tmp_heap.pop();		} while(result_heap.size()){cout<<result_heap.top()<<" ";result_heap.pop();}return 0;
}
提交結果

方法2:只建一個堆

只建小根堆,由題目的"單調不降序列"

先將a[i]+b[0]入堆(堆中元素正好N個),之后每次先出堆頂元素,再入剩下的元素(a[i]+b[1]、a[i]+b[2]、...、a[i]+b[n]),這樣每次出堆的元素都是當前堆中最小的,執行N次出堆即可,時間復雜度為O(NlogN)

以題目的測試用例為例

2+1=3 6+1=7 6+1=7

2+4=6 6+4=10 6+4=10

2+8=10 6+8=14 6+8=14

一行一行看,會發現:

a[1] + b[1] ≤ a[1] + b[2] ≤ a[1] + b[3] ≤ ... ≤ a[1] + b[n]
a[2] + b[1] ≤ a[2] + b[2] ≤ a[2] + b[3] ≤ ... ≤ a[2] + b[n]
a[3] + b[1] ≤ a[3] + b[2] ≤ a[3] + b[3] ≤ ... ≤ a[3] + b[n]
......

先將a[i]+b[1]入堆(因為是每一行不等式中最小的那個),之后取堆頂元素后再入堆,執行N次

能只將和入堆嗎?如果不用兩重循環的話

答:不能,只將和入堆會找不到下一個入堆的元素,入堆的應該是結構體

代碼

#include <iostream>
#include <queue>
using namespace std;
const int N1=1e6+10;
int n,a[N1],b[N1];
struct node
{int i;int j;int sum;bool operator<(const node& x)const{return sum>x.sum;	}	
};priority_queue<node> heap; 
int main() 
{cin>>n;for (int i=0;i<n;i++)cin>>a[i];for (int i=0;i<n;i++)cin>>b[i];//前n個入堆for (int i=0;i<n;i++){heap.push({i,0,a[i]+b[0]}); }	//剩下的入堆for (int k=0;k<n;k++){node tmp=heap.top();heap.pop();		cout<<tmp.sum<<" ";if (tmp.j+1<n) {heap.push({tmp.i,tmp.j+1,a[tmp.i]+b[tmp.j+1]}); }} return 0;
}

提交結果

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/905967.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/905967.shtml
英文地址,請注明出處:http://en.pswp.cn/news/905967.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

題單:表達式求值1

題目描述 給定一個只包含 “加法” 和 “乘法” 的算術表達式&#xff0c;請你編程計算表達式的值。 輸入格式 輸入僅有一行&#xff0c;為需要計算的表達式&#xff0c;表達式中只包含數字、加法運算符 和乘法運算符 *&#xff0c;且沒有括號。 所有參與運算的數字不超過…

DeepSeek超大模型的高效訓練策略

算力挑戰 訓練DeepSeek此類千億乃至萬億級別參數模型,對算力資源提出了極高要求。以DeepSeek-V3為例,其基礎模型參數量為67億,采用專家混合(MoE)架構后實際激活參數可達幾百億。如此規模的模型遠超單張GPU顯存容量極限,必須借助分布式并行才能加載和訓練。具體挑戰主要包…

MFC中DoDataExchange的簡明指南

基本概念 DoDataExchange 是 MFC 框架中實現數據自動同步的核心函數&#xff0c;主要用于對話框中控件與成員變量的雙向綁定。它能讓控件中的數據和成員變量自動保持一致&#xff0c;無需手動讀寫控件數據。 使用示例 1&#xff09;變量聲明 在對話框頭文件中聲明與控件對應…

FreeCAD源碼分析: Transaction實現原理

本文闡述FreeCAD中Transaction的實現原理。 注1&#xff1a;限于研究水平&#xff0c;分析難免不當&#xff0c;歡迎批評指正。 注2&#xff1a;文章內容會不定期更新。 一、概念 Ref. from What is a Transaction? A transaction is a group of operations that have the f…

C++類與對象--1 特性一:封裝

C面向對象三大特性&#xff1a; &#xff08;1&#xff09;封裝&#xff1b;&#xff08;2&#xff09;繼承&#xff1b;&#xff08;3&#xff09;多態&#xff1b; C認為萬物皆是對象&#xff0c;對象上有對應的屬性&#xff08;數據&#xff09;和行為&#xff08;方法&…

初探Reforcement Learning強化學習【QLearning/Sarsa/DQN】

文章目錄 一、Q-learning現實理解&#xff1a;舉例&#xff1a;回顧&#xff1a; 二、Sarsa和Q-learning的區別 三、Deep Q-NetworkDeep Q-Network是如何工作的&#xff1f;前處理&#xff1a;Convolution NetworksExperience Replay 一、Q-learning 是RL中model-free、value-…

WebRTC技術EasyRTC嵌入式音視頻通信SDK打造遠程實時視頻通話監控巡檢解決方案

一、方案概述? 在現代工業生產、基礎設施維護等領域&#xff0c;遠程監控與巡檢工作至關重要。傳統的監控與巡檢方式存在效率低、成本高、實時性差等問題。EasyRTC作為一種先進的實時音視頻通信技術&#xff0c;具備低延遲、高穩定性、跨平臺等特性&#xff0c;能夠有效解決這…

專題四:綜合練習(括號組合算法深度解析)

以leetcode22題為例 題目分析&#xff1a; 給一個數字n&#xff0c;返回合法的所有的括號組合 算法原理分析&#xff1a; 你可以先考慮如何不重不漏的羅列所有的括號組合 清楚什么是有效的括號組合&#xff1f;&#xff1f;&#xff1f; 1.所有的左括號的數量等于右括號的…

星云智控自定義物聯網實時監控模板-為何成為痛點?物聯網設備的多樣化-優雅草卓伊凡

星云智控自定義物聯網實時監控模板-為何成為痛點&#xff1f;物聯網設備的多樣化-優雅草卓伊凡 引言&#xff1a;物聯網監控的模板革命 在萬物互聯的時代&#xff0c;設備監控已成為保障物聯網系統穩定運行的核心環節。傳統的標準化監控方案正面臨著設備類型爆炸式增長帶來的…

5.27本日總結

一、英語 復習list2list29 二、數學 學習14講部分內容 三、408 學習計組1.2內容 四、總結 高數和計網明天結束當前章節&#xff0c;計網內容學完之后主要學習計組和操作系統 五、明日計劃 英語&#xff1a;復習lsit3list28&#xff0c;完成07年第二篇閱讀 數學&#…

幾種運放典型應用電路

運算放大器簡稱:OP、OPA、OPAMP、運放。 一、電壓跟隨器 電壓跟隨器顧名思義運放的輸入端電壓與運放的輸出電壓相等 這個電路一般應用目的是增加電壓驅動能力: 比如說有個3V電源,借一個負載,隨著負載電流變大,3V就會變小說明3V電源帶負載能力小,驅動能力弱,這個時候…

Android核心系統服務:AMS、WMS、PMS 與 system_server 進程解析

1. 引言 在 Android 系統中&#xff0c;ActivityManagerService (AMS)、WindowManagerService (WMS) 和 PackageManagerService (PMS) 是三個最核心的系統服務&#xff0c;它們分別管理著應用的生命周期、窗口顯示和應用包管理。 但你是否知道&#xff0c;這些服務并不是獨立…

從另一個視角理解TCP握手、揮手與可靠傳輸

本文將深入探討 TCP 協議中三次握手、四次揮手的原理&#xff0c;以及其保證可靠傳輸的機制。 一、三次握手&#xff1a;為何是三次&#xff0c;而非兩次&#xff1f; 建立 TCP 連接的過程猶如一場嚴謹的 “對話”&#xff0c;需要經過三次握手才能確保通信雙方的可靠連接。 三…

將Docker compose 部署的夜鶯V6版本升到V7版本的詳細步驟、常見問題解答及相關鏡像下載地址

環境說明 夜鶯官網&#xff1a;首頁 - 快貓星云Flashcat 夜鶯安裝程序下載地址&#xff1a;快貓星云下載中心 夜鶯v7.7.2鏡像&#xff08;X86架構&#xff09;&#xff1a; https://download.csdn.net/download/jjk_02027/90851161 夜鶯ibex v1.2.0鏡像&#xff08;X86架構…

JavaScript【4】數組和其他內置對象(API)

1.數組: 1.概述: js中數組可理解為一個存儲數據的容器,但與java中的數組不太一樣;js中的數組更像java中的集合,因為此集合在創建的時候,不需要定義數組長度,它可以實現動態擴容;js中的數組存儲元素時,可以存儲任意類型的元素,而java中的數組一旦創建后,就只能存儲定義類型的元…

永久免費!專為 Apache Doris 打造的可視化數據管理工具 SelectDB Studio V1.1.0 重磅發布!

作為全球領先的開源實時數據倉庫&#xff0c; Apache Doris Github Stars 已超過 13.6k&#xff0c;并在 5000 余家中大型企業生產環境得到廣泛應用&#xff0c;支撐業務核心場景&#xff0c;成為眾多企業數據分析基礎設施不可或缺的重要基座。過去&#xff0c;Apache Doris 用…

數字萬用表與指針萬用表使用方法及注意事項

在電子測量領域&#xff0c;萬用表是極為常用的工具&#xff0c;數字萬用表和指針萬用表各具特點。熟練掌握它們的使用方法與注意事項&#xff0c;能確保測量的準確性與安全性。下面為您詳細介紹&#xff1a; 一 、數字萬用表按鈕功能 > 進入及退出手動量程模式 每 按 […

深度學習Dropout實現

深度學習中的 Dropout 技術在代碼層面上的實現通常非常直接。其核心思想是在訓練過程中&#xff0c;對于網絡中的每個神經元&#xff08;或者更精確地說&#xff0c;是每個神經元的輸出&#xff09;&#xff0c;以一定的概率 p 隨機將其輸出置為 0。在反向傳播時&#xff0c;這…

AtCoder AT_abc406_c [ABC406C] ~

前言 除了 A 題&#xff0c;唯一一道一遍過的題。 題目大意 我們定義滿足以下所有條件的一個長度為 N N N 的序列 A ( A 1 , A 2 , … , A N ) A(A_1,A_2,\dots,A_N) A(A1?,A2?,…,AN?) 為波浪序列&#xff1a; N ≥ 4 N\ge4 N≥4&#xff08;其實滿足后面就必須滿足這…

Java Web 應用安全響應頭配置全解析:從單體到微服務網關的實踐

背景&#xff1a;為什么安全響應頭至關重要&#xff1f; 在 Web 安全領域&#xff0c;響應頭&#xff08;Response Headers&#xff09;是防御 XSS、點擊劫持、跨域數據泄露等攻擊的第一道防線。通過合理配置響應頭&#xff0c;可強制瀏覽器遵循安全策略&#xff0c;限制惡意行…