<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      8.13信息學(xué)集訓(xùn)_數(shù)據(jù)結(jié)構(gòu)

      預(yù)習(xí)筆記

      棧與隊(duì)列_基礎(chǔ)1

      單調(diào)棧與單調(diào)隊(duì)列

      鏈表、棧、隊(duì)列

      B3631 單向鏈表

      實(shí)現(xiàn)一個(gè)數(shù)據(jù)結(jié)構(gòu),維護(hù)一張表(最初只有一個(gè)元素 \(1\))。需要支持下面的操作,其中 \(x\)\(y\) 都是 \(1\)\(10^6\) 范圍內(nèi)的正整數(shù),且保證任何時(shí)間表中所有數(shù)字均不相同,操作數(shù)量不多于 \(10^5\)

      • 1 x y :將元素 \(y\) 插入到 \(x\) 后面;
      • 2 x :詢問 \(x\) 后面的元素是什么。如果 \(x\) 是最后一個(gè)元素,則輸出 \(0\)
      • 3 x:從表中刪除元素 \(x\) 后面的那個(gè)元素,不改變其他元素的先后順序。

      輸入格式:第一行一個(gè)整數(shù) \(q\) 表示操作次數(shù);接下來 \(q\) 行,每行表示一次操作,操作具體間題目描述。
      輸出格式:對于每個(gè)操作 2,輸出一個(gè)數(shù)字,用換行隔開。

      輸入樣例 輸出樣例
      6
      1 1 99
      1 99 50
      1 99 75
      2 99
      3 75
      2 1
      
      75
      99
      

      【分析】模擬一個(gè)鏈表,但是需要支持 \(O(1)\) 的查詢,因?yàn)?\(x,y\in [1,10^6]\),所以使用 \(h[x]=idx\) 來記錄 \(x\) 是那個(gè)節(jié)點(diǎn)。

      單向鏈表的實(shí)現(xiàn)

      #include <bits/stdc++.h>
      using namespace std;
      typedef long long ll;
      const int N = 1e6 + 10, INF = 0x3f3f3f3f;
      struct Node {
          int r, v;
      } e[N];
      int h[N], idx;
      // h[x] 表示 x 所在節(jié)點(diǎn)下標(biāo)
      void insert(int x, int y) {
          h[y] = ++idx;
          e[h[y]] = {e[h[x]].r, y};
          e[h[x]].r = h[y];
      }
      int find(int x) {
          if (e[h[x]].r == 0) return 0;
          return e[e[h[x]].r].v;
      }
      void del(int x) {
          if (e[h[x]].r == 0) return;
          e[h[x]].r = e[e[h[x]].r].r;
      }
      int main() {
          int q, op, x, y; cin >> q, insert(0, 1);
          while (q--) {
              cin >> op >> x;
              switch (op) {
                  case 1: cin >> y, insert(x, y); break;
                  case 2: cout << find(x) << endl; break;
                  case 3: del(x); break;
              }
          }
          return 0;
      }
      

      以下是雙向鏈表的實(shí)現(xiàn)

      struct Node {
          int l, r, v;
      } e[N];
      int h[N], idx;
      // h[x] 表示 x 所在節(jié)點(diǎn)下標(biāo)
      void insert(int x, int y) {
          h[y] = ++idx;
          e[h[y]] = {h[x], e[h[x]].r, y};
          e[e[h[x]].r].l = e[h[x]].r = h[y];
      }
      int find(int x) {
          if (e[h[x]].r == 0) return 0;
          return e[e[h[x]].r].v;
      }
      void del(int x) {
          e[e[h[x]].r].l = h[x];
          e[h[x]].r = e[e[h[x]].r].r;
      }
      

      P1981 [NOIP2013 普及組] 表達(dá)式求值

      給定一個(gè)只包含加法和乘法的算術(shù)表達(dá)式,請你編程計(jì)算表達(dá)式的值。
      輸入一行需要計(jì)算的表達(dá)式,表達(dá)式中只包含數(shù)字、加法運(yùn)算符‘+’和乘法運(yùn)算符‘×’,且沒有括號,所有參與運(yùn)算的數(shù)字均為 0 到 pow(2,31)-1之間的整數(shù)。輸入數(shù)據(jù)保證這一行只有 0-9、+、× 這12種字符。
      輸出一個(gè)整數(shù),表示這個(gè)表達(dá)式的值,當(dāng)答案長度多于4位時(shí),請只輸出最后4位,前導(dǎo)0不輸出。

      輸入樣例:1+1*3+4
      輸出樣例:8
      

      【分析】模擬/棧
      先觀察輸入數(shù)據(jù)的格式,一定是:a+b+b+b...
      那么可以考慮先讀入 a,后面死循環(huán)讀入 +b,這樣就可以輕松完成數(shù)據(jù)分割。

      由于有 *+,可以將 * 先處理了,后面對于 + 直接累加即可。
      構(gòu)建一個(gè)數(shù)字棧,遍歷字符串,數(shù)字直接入棧;如果是運(yùn)算符,將當(dāng)前棧頂元素 ab進(jìn)行計(jì)算,同時(shí)pop,計(jì)算的結(jié)果push。
      最后累加棧內(nèi)全部元素即可。

      點(diǎn)擊查看代碼
      #include<bits/stdc++.h>
      using namespace std;
      stack<long long> sta;
      int a,b,ans=0, mod=10000;  char ch;
      int main() {
          cin>>a;  a %= mod;  sta.push(a);
          while(cin>>ch>>b) {
              b %= mod;
              if(ch=='*') {
                  a = sta.top();  sta.pop();
                  sta.push(a*b%mod);
              } else if(ch=='+') { sta.push(b); }
          }
          while(!sta.empty()) {
              ans += sta.top(), sta.pop();
              ans %= mod;
          }
          cout<<ans%mod;    return 0;
      }
      

      P1449 后綴表達(dá)式

      所謂后綴表達(dá)式是指這樣的一個(gè)表達(dá)式:式中不再引用括號,運(yùn)算符號放在兩個(gè)運(yùn)算對象之后,所有計(jì)算按運(yùn)算符號出現(xiàn)的順序,嚴(yán)格地由左而右新進(jìn)行(不用考慮運(yùn)算符的優(yōu)先級)。
      如:3*(5–2)+7 對應(yīng)的后綴表達(dá)式為:3.5.2.-*7.+@。
      '@'為表達(dá)式的結(jié)束符號,'.'為操作數(shù)的結(jié)束符號。字符串長度在1000內(nèi)。

      輸入格式:后綴表達(dá)式
      輸出格式:表達(dá)式的值

      輸入樣例:3.5.2.-*7.+@
      輸出樣例:16
      

      【分析】模擬/棧
      先觀察輸入數(shù)據(jù)的格式,一定是:a.a.+@
      每個(gè)數(shù)字后面有一個(gè) .,可以據(jù)此進(jìn)行數(shù)據(jù)分割。

      構(gòu)建一個(gè)數(shù)字棧,遍歷字符串,數(shù)字直接入棧;
      如果是運(yùn)算符,將順序取出兩個(gè)棧頂元素 a,b 進(jìn)行計(jì)算,計(jì)算的結(jié)果push。
      最后棧頂元素就是答案。

      點(diǎn)擊查看代碼
      #include<bits/stdc++.h>
      using namespace std;
      stack<int> sta;  int a,b,c;  char ch;
      int main(){
          while((ch=getchar())!='@'){
              if(ch<='9' && ch>='0'){
                  a=a*10+ch-'0';
              }else if(ch=='.'){
                  sta.push(a);  a=0;
              }else {
                  a=sta.top(),sta.pop();
                  b=sta.top(),sta.pop();
                  if(ch=='+'){ c = b+a; }
                  else if(ch=='-'){ c = b-a; }
                  else if(ch=='*'){ c = b*a; }
                  else if(ch=='/'){ c = b/a; }
                  sta.push(c);  a=b=0;
              }
          }
          cout<<c<<endl;  return 0;
      }
      

      P5788 【模板】單調(diào)棧

      給出項(xiàng)數(shù)為 \(n\) 的整數(shù)數(shù)列 \(a_{1 \dots n}\)
      定義函數(shù) \(f(i)\) 代表數(shù)列中第 \(i\) 個(gè)元素之后第一個(gè)大于 \(a_i\) 的元素的下標(biāo),即 \(f(i)=\min_{i<j\leq n, a_j > a_i} \{j\}\)。若不存在,則 \(f(i)=0\)

      試求出 \(f(1\dots n)\)

      輸入格式:第一行一個(gè)正整數(shù) \(n\)。第二行 \(n\) 個(gè)正整數(shù) \(a_{1\dots n}\)
      輸出格式:一行 \(n\) 個(gè)整數(shù) \(f(1\dots n)\) 的值。

      輸入樣例 輸出樣例
      5
      1 4 2 3 5
      
      2 5 4 5 0
      

      【數(shù)據(jù)范圍】對于 \(100\%\) 的數(shù)據(jù),\(1 \le n\leq 3\times 10^6\)\(1\leq a_i\leq 10^9\)

      【分析】

      • 求每個(gè)元素右邊第一個(gè)大于該元素的值的下標(biāo)。
      • 維護(hù)一個(gè)單調(diào)棧,可以畫一下下面這個(gè)圖。

      image

      上圖是從左向右遍歷的單調(diào)遞減棧,也可以維護(hù)一個(gè)從右向左遍歷的單調(diào)遞增棧。

      #include <bits/stdc++.h>
      using namespace std;
      typedef long long ll;
      const int N = 3e6 + 10, INF = 0x3f3f3f3f;
      int n, a[N], st[N], hh, ans[N];
      
      int main() {
          cin >> n;
          for (int i = 1; i <= n; i++)
              cin >> a[i];
          // 從左向右 : 維護(hù)一個(gè)單減棧
          for (int i = 1; i <= n; i++) {
              while (hh && a[st[hh]] < a[i]) {
                  ans[st[hh]] = i;
                  hh--;
              }
              st[++hh] = i;
          }
          // 從右向左 : 維護(hù)一個(gè)單增棧
          /*hh = 0;
          for (int i = n; i >= 1; i--) {
              while (hh && a[st[hh]] <= a[i])
                  hh--;
              ans[i] = st[hh];
              st[++hh] = i;
          }*/
      
          for (int i = 1; i <= n; i++)
              cout << ans[i] << " \n"[i == n];
          return 0;
      }
      

      P1886 滑動窗口 /【模板】單調(diào)隊(duì)列

      有一個(gè)長為 \(n\) 的序列 \(a\),以及一個(gè)大小為 \(k\) 的窗口。現(xiàn)在這個(gè)從左邊開始向右滑動,每次滑動一個(gè)單位,求出每次滑動后窗口中的最大值和最小值。

      例如:The array is \([1,3,-1,-3,5,3,6,7]\), and \(k = 3\)

      輸入格式: 輸入一共有兩行,第一行有兩個(gè)正整數(shù) \(n,k\)。第二行 \(n\) 個(gè)整數(shù),表示序列 \(a\)
      輸出格式:輸出共兩行,第一行為每次窗口滑動的最小值;第二行為每次窗口滑動的最大值

      輸入樣例 輸出樣例
      8 3
      1 3 -1 -3 5 3 6 7
      
      -1 -3 -3 -3 3 3
      3 3 5 5 6 7
      

      【數(shù)據(jù)范圍】\(1\le k \le n \le 10^6\)\(a_i \in [-2^{31},2^{31})\)

      【分析】考慮兩個(gè)問題

      1. 如何確定窗口大小:可以通過下標(biāo)求差完成
      2. 如何確定窗口內(nèi)的最值:可以利用單調(diào)隊(duì)列完成

      這里為了便于理解,我們畫一個(gè)樣例圖

      image

      #include <bits/stdc++.h>
      using namespace std;
      typedef long long ll;
      const int N = 1e6 + 10, INF = 0x3f3f3f3f;
      int n, m, a[N], q[N], ans[N];
      
      int main() {
          cin >> n >> m;
          for (int i = 1; i <= n; i++)
              cin >> a[i];
      
          // 最小值 - 維護(hù)一個(gè)單調(diào)遞增隊(duì)列
          int hh = 0, tt = -1;
          for (int i = 1; i <= n; i++) {
              while (hh <= tt && a[q[tt]] >= a[i]) tt--;
              while (hh <= tt && i - q[hh] + 1 > m) hh++;
              q[++tt] = i;
              if (i >= m)
                  cout << a[q[hh]] << " \n"[i == n];
          }
      
          // 最大值 - 維護(hù)一個(gè)單調(diào)遞減隊(duì)列
          hh = 0, tt = -1;
          for (int i = 1; i <= n; i++) {
              while (hh <= tt && a[q[tt]] <= a[i]) tt--;
              while (hh <= tt && i - q[hh] + 1 > m) hh++;
              q[++tt] = i;
              if (i >= m)
                  cout << a[q[hh]] << " \n"[i == n];
          }
          return 0;
      }
      

      P1901 發(fā)射站

      某地有 \(N\) 個(gè)能量發(fā)射站排成一行,每個(gè)發(fā)射站 \(i\) 都有不相同的高度 \(H_i\),并能向兩邊(兩端的發(fā)射站只能向一邊)同時(shí)發(fā)射能量值為 \(V_i\) 的能量,發(fā)出的能量只被兩邊最近的且比它高的發(fā)射站接收。顯然,每個(gè)發(fā)射站發(fā)來的能量有可能被 \(0\)\(1\)\(2\) 個(gè)其他發(fā)射站所接受。

      請計(jì)算出接收最多能量的發(fā)射站接收的能量是多少。

      輸入格式:第 \(1\) 行一個(gè)整數(shù) \(N\)。第 \(2\)\(N+1\) 行,第 \(i+1\) 行有兩個(gè)整數(shù) \(H_i\)\(V_i\),表示第 \(i\) 個(gè)人發(fā)射站的高度和發(fā)射的能量值。
      輸出格式:輸出僅一行,表示接收最多能量的發(fā)射站接收到的能量值。答案不超過 32 位帶符號整數(shù)的表示范圍。

      輸入樣例 輸出樣例
      3
      4 2 
      3 5 
      6 10
      
      7
      

      【數(shù)據(jù)范圍】\(1\le N\le 10^6,1\le H_i\le 2\times 10^9,1\le V_i\le 10^4\)

      【分析】

      • 法1:直接暴力模擬,左右查找合適的值,可以過 40%,會 TLE。
      • 法2:維護(hù)單調(diào)棧(單調(diào)遞減棧:棧底到棧頂元素單調(diào)遞減)

      image

      #include<bits/stdc++.h>
      using namespace std;
      typedef long long LL;
      const int N=1e6+10,INF=0x3f3f3f3f;
      int n,h[N],v[N],st[N],head=0;
      LL ans[N];
      
      void slove1() { // 預(yù)計(jì) TLE
          for(int i=1; i<=n; i++) {
              int l=i-1, r=i+1;
              while(l>0 && h[l]<=h[i]) l--;
              while(r<=n && h[r]<=h[i]) r++;
              ans[l]+=v[i], ans[r]+=v[i];
          }
      }
      void slove2() { // 維護(hù)一個(gè)單調(diào)棧
          for(int i=1; i<=n; i++) {
              while(head && h[st[head]] < h[i]) {
                  ans[i] += v[st[head]], head--;
              }
              ans[st[head]] += v[i];
              st[++head] = i;
          }
      }
      int main() {
          scanf("%d",&n);
          for(int i=1; i<=n; i++) scanf("%d%d",&h[i],&v[i]);
          slove1();
          for(int i=1; i<=n; i++) ans[1]=max(ans[1],ans[i]);
          printf("%lld\n",ans[1]);
          return 0;
      }
      

      P1540 [NOIP2010 提高組] 機(jī)器翻譯

      翻譯軟件從頭到尾,依次將每個(gè)英文單詞用對應(yīng)的中文含義來替換。對于每個(gè)英文單詞,軟件會先在內(nèi)存中查找這個(gè)單詞的中文含義,如果內(nèi)存中有,軟件就會用它進(jìn)行翻譯;如果內(nèi)存中沒有,軟件就會在外存中的詞典內(nèi)查找,查出單詞的中文含義然后翻譯,并將這個(gè)單詞和譯義放入內(nèi)存,以備后續(xù)的查找和翻譯。

      假設(shè)內(nèi)存中有 \(M\) 個(gè)單元,每單元能存放一個(gè)單詞和譯義。每當(dāng)軟件將一個(gè)新單詞存入內(nèi)存前,如果當(dāng)前內(nèi)存中已存入的單詞數(shù)不超過 \(M-1\),軟件會將新單詞存入一個(gè)未使用的內(nèi)存單元;若內(nèi)存中已存入 \(M\) 個(gè)單詞,軟件會清空最早進(jìn)入內(nèi)存的那個(gè)單詞,騰出單元來,存放新單詞。

      假設(shè)一篇英語文章的長度為 \(N\) 個(gè)單詞。給定這篇待譯文章,翻譯軟件需要去外存查找多少次詞典?假設(shè)在翻譯開始前,內(nèi)存中沒有任何單詞。

      輸入格式:共 \(2\) 行。每行中兩個(gè)數(shù)之間用一個(gè)空格隔開。
      第一行為兩個(gè)正整數(shù) \(M,N\),代表內(nèi)存容量和文章的長度。
      第二行為 \(N\) 個(gè)非負(fù)整數(shù),按照文章的順序,每個(gè)數(shù)(大小不超過 \(1000\))代表一個(gè)英文單詞。文章中兩個(gè)單詞是同一個(gè)單詞,當(dāng)且僅當(dāng)它們對應(yīng)的非負(fù)整數(shù)相同。

      輸出格式:一個(gè)整數(shù),為軟件需要查詞典的次數(shù)。

      輸入樣例 輸出樣例
      3 7
      1 2 1 5 4 4 1
      
      5
      

      【數(shù)據(jù)范圍】\(1 \leq M \leq 100\)\(1 \leq N \leq 1000\)

      數(shù)組模擬隊(duì)列

      #include <bits/stdc++.h>
      using namespace std;
      typedef long long ll;
      const int N = 1e6 + 10, INF = 0x3f3f3f3f;
      int n, m, a[N], st[N], q[N], hh, tt = -1, ans;
      int main() {
          cin >> m >> n;
          for (int i = 1, x; i <= n; i++) {
              cin >> x, a[i] = x;
              if (!st[x]) {
                  while (tt - hh + 1 >= m) st[q[hh++]] = 0;
                  q[++tt] = x, ans++, st[x] = 1;
              }
          }
          cout << ans;
          return 0;
      }
      

      使用STL

      點(diǎn)擊查看代碼
      #include <bits/stdc++.h>
      using namespace std;
      const int N = 1e6 + 10;
      int m, n, v, ans; bool st[N];
      queue<int> q;
      int main() {
          scanf("%d%d", &m, &n);
          for (int i = 1; i <= n; i++) {
              scanf("%d", &v);
              if (st[v]) continue;
              q.push(v), ans++, st[v] = 1;
              while (q.size() > m)
                  st[q.front()] = 0, q.pop();
          }
          printf("%d\n", ans);
          return 0;
      }
      

      優(yōu)先隊(duì)列、堆

      P2085 最小函數(shù)值

      \(n\) 個(gè)函數(shù),分別為 \(F_1,F_2,\dots,F_n\)。定義 \(F_i(x)=A_ix^2+B_ix+C_i(x\in\mathbb N*)\)。給定這些 \(A_i\)\(B_i\)\(C_i\),請求出所有函數(shù)的所有函數(shù)值中最小的 \(m\) 個(gè)(如有重復(fù)的要輸出多個(gè))。

      輸入格式:第一行輸入兩個(gè)正整數(shù) \(n\)\(m\),以下 \(n\) 行每行三個(gè)正整數(shù),其中第 \(i\) 行的三個(gè)數(shù)分別為 \(A_i\)\(B_i\)\(C_i\)
      輸出格式:輸出將這 \(n\) 個(gè)函數(shù)所有可以生成的函數(shù)值排序后的前 \(m\) 個(gè)元素。這 \(m\) 個(gè)數(shù)應(yīng)該輸出到一行,用空格隔開。

      輸入樣例 輸出樣例
      3 10
      4 5 3
      3 4 5
      1 7 1
      
      9 12 12 19 25 29 31 44 45 54
      

      【數(shù)據(jù)范圍】 \(1 \leq n,m\le10000\)\(1 \leq A_i\le10,B_i\le100,C_i\le10^4\)

      點(diǎn)擊查看代碼
      #include <bits/stdc++.h>
      using namespace std;
      typedef long long ll;
      const int N = 1e6 + 10, INF = 0x3f3f3f3f;
      int n, m, a[N], b[N], c[N];
      
      namespace BF {
      void solve() {
          priority_queue<int, vector<int>, greater<int>> q;  // down
          for (int x = 1; x <= m; x++)
              for (int i = 1; i <= n; i++) {
                  int t = a[i] * x * x + b[i] * x + c[i];
                  q.push(t);
              }
          while (m--) {
              cout << q.top() << " ";
              q.pop();
          }
      }
      };  // namespace BF
      
      namespace BF2 {
      struct T {
          int a, b, c, x;
          int cal() const { return a * x * x + b * x + c; }
          bool operator<(const T& t) const { return cal() > t.cal(); }
      };
      void solve() {
          priority_queue<T> q;
          for (int i = 1; i <= n; i++)
              q.push({a[i], b[i], c[i], 1});
      
          while (m--) {
              T t = q.top();
              cout << t.cal() << " ";
              t.x++, q.push(t), q.pop();
          }
      }
      };  // namespace BF2
      
      int main() {
          cin >> n >> m;
          for (int i = 1; i <= n; i++)
              cin >> a[i] >> b[i] >> c[i];
          BF2::solve();
          return 0;
      }
      

      P1090 [NOIP2004 提高組] 合并果子 / [USACO06NOV] Fence Repair G

      \(n\) 堆果子經(jīng)過 \(n-1\) 次合并后, 剩下一堆,把兩堆果子合并到一起,消耗的體力等于兩堆果子的重量之和。求最小消耗體力。
      輸入格式:第一行是一個(gè)整數(shù) n ,表示果子的種類數(shù)。
      第二行包含 n個(gè)整數(shù),第 i 個(gè)整數(shù) \(a_i\) 是第 i 種果子的數(shù)目。
      輸出格式:最小的體力耗費(fèi)值。輸入數(shù)據(jù)保證這個(gè)值小于 \(2^{31}\)

      說明/提示:\(1 ≤ n ≤ 10000, 1 ≤ a_i ≤ 20000\)

      【分析】貪心策略:每次選擇最小的兩個(gè)元素進(jìn)行合并。

      P6033 [NOIP2004 提高組] 合并果子 加強(qiáng)版

      【數(shù)據(jù)規(guī)模與約定】

      • Subtask 1(10 points):\(1 \leq n \leq 8\)
      • Subtask 2(20 points):\(1 \leq n \leq 10^3\)
      • Subtask 3(30 points):\(1 \leq n \leq 10^5\)
      • Subtask 4(40 points):\(1 \leq n \leq 10^7\)

      對于全部的測試點(diǎn),保證 \(1 \leq a_i \leq 10^5\)

      【分析】\(10^7\),使用堆排序 \(O(nlog)\) 無法通過,考慮 \(O(n)\)

      切入點(diǎn):\(1 \leq a_i \leq 10^5\) ,單個(gè)元素大小較小,可以使用計(jì)數(shù)排序進(jìn)行第一次處理,但是后續(xù)的還需要插入 \(n-1\) 怎么排序呢?

      • 思路1:整體有序,插入一個(gè)新生成的數(shù)據(jù),可以考慮插入排序優(yōu)化,但是還是會TLE。

      • 思路2:原數(shù)據(jù)排序后升序,新生成的數(shù)據(jù)一定是遞增的,考慮分別維護(hù)單調(diào)遞增隊(duì)列1、2,每次選擇隊(duì)首最小的2個(gè)元素,進(jìn)行合并,之后在插入隊(duì)列2。復(fù)雜度分析:計(jì)數(shù)排序 \(O(n)\),維護(hù)兩個(gè)隊(duì)列 \(O(n)\),整體復(fù)雜度 \(O(n)\)

      點(diǎn)擊查看代碼
      #include <bits/stdc++.h>
      using namespace std;
      typedef long long ll;
      const int N = 1e7 + 5, INF = 0x3f3f3f3f;
      int n, a[N];
      
      namespace IO {
      ll read() {
          ll v = 0, f = 1; char c = getchar();
          while (c < '0' || c > '9') {
              if (c == '-') f = -1;
              c = getchar();
          }
          while (c >= '0' && c <= '9')
              v = v * 10 + c - '0', c = getchar();
          return v * f;
      }
      };  // namespace IO
      
      namespace Heap {
      void solve() {
          priority_queue<int, vector<int>, greater<int>> q;
          for (int i = 1; i <= n; i++) q.push(a[i]);
          int ans = 0, a, b;
          while (q.size() > 1) {
              a = q.top(), q.pop();
              b = q.top(), q.pop();
              q.push(a + b), ans += a + b;
          }
          cout << ans << endl;
      }
      };  // namespace Heap
      namespace Queue {
      void solve() {
          vector<int> st(1e5 + 5, 0);
          queue<ll> q1, q2;
          for (int i = 1; i <= n; i++) st[a[i]]++;
          for (int i = 1; i <= 1e5; i++)
              while (st[i]--) q1.push(i);
          ll ans = 0, x, y;
          for (int i = 1; i < n; i++) {
              if (q2.empty() || q1.size() && q1.front() < q2.front())
                  x = q1.front(), q1.pop();
              else x = q2.front(), q2.pop();
      
              if (q2.empty() || q1.size() && q1.front() < q2.front())
                  y = q1.front(), q1.pop();
              else y = q2.front(), q2.pop();
              ans += x + y, q2.push(x + y);
          }
          cout << ans << endl;
      }
      };  // namespace Queue
      int main() {
          // using namespace IO;
          // n = read();
          // for (int i = 1; i <= n; i++)
          //     a[i] = read();
          scanf("%d", &n);
          for (int i = 1; i <= n; i++)
              scanf("%d", &a[i]);
          // Heap::solve();
          Queue::solve();
          return 0;
      }
      

      P1631 序列合并

      有兩個(gè)長度為 \(N\)單調(diào)不降序列 \(A,B\),在 \(A,B\) 中各取一個(gè)數(shù)相加可以得到 \(N^2\) 個(gè)和,求這 \(N^2\) 個(gè)和中最小的 \(N\) 個(gè)。

      輸入格式:第一行一個(gè)正整數(shù) \(N\),第二行 \(N\) 個(gè)整數(shù) \(A_{1\dots N}\),第三行 \(N\) 個(gè)整數(shù) \(B_{1\dots N}\)
      輸出格式:一行 \(N\) 個(gè)整數(shù),從小到大表示這 \(N\) 個(gè)最小的和。

      輸入樣例 輸出樣例
      3
      2 6 6
      1 4 8
      
      3 6 7
      

      【數(shù)據(jù)范圍】\(1 \le N \le 10^5\)\(1 \le a_i,b_i \le 10^9\)

      【分析】看圖說話,哪里存在答案?

      image

      點(diǎn)擊查看代碼
      #include <bits/stdc++.h>
      using namespace std;
      typedef long long ll;
      const int N = 3e6 + 10, INF = 0x3f3f3f3f;
      int n, a[N], b[N];
      priority_queue<int, vector<int>, greater<int>> q;
      
      int main() {
          cin >> n;
          for (int i = 1; i <= n; i++) cin >> a[i];
          for (int i = 1; i <= n; i++) cin >> b[i];
          for (int i = 1; i <= n; i++)
              for (int j = 1; j <= n / i; j++)
                  q.push(a[i] + b[j]);
          for (int i = 1; i <= n; i++)
              cout << q.top() << " \n"[i == n], q.pop();
          return 0;
      }
      

      P2251 質(zhì)量檢測

      為了檢測生產(chǎn)流水線上總共 \(N\) 件產(chǎn)品的質(zhì)量,我們首先給每一件產(chǎn)品打一個(gè)分?jǐn)?shù) \(A\) 表示其品質(zhì),然后統(tǒng)計(jì)前 \(M\) 件產(chǎn)品中質(zhì)量最差的產(chǎn)品的分值 \(Q[m] = min\{A_1, A_2, ... A_m\}\),以及第 2 至第 \(M + 1\) 件的 $Q[m + 1], Q[m + 2] $... 最后統(tǒng)計(jì)第 \(N - M + 1\) 至第 \(N\) 件的 \(Q[n]\)。根據(jù) \(Q\) 再做進(jìn)一步評估。

      請你盡快求出 \(Q\) 序列。

      輸入格式:輸入共兩行,第一行共兩個(gè)數(shù) \(N\)\(M\),由空格隔開,含義如前述;第二行共 \(N\) 個(gè)數(shù),表示 \(N\) 件產(chǎn)品的質(zhì)量。

      輸出格式:輸出共 \(N - M + 1\) 行,第 1 至 \(N - M + 1\) 行每行一個(gè)數(shù),第 \(i\) 行的數(shù) \(Q[i + M - 1]\)。含義如前述。

      輸入樣例 輸出樣例
      10 4
      16 5 6 9 5 13 14 20 8 12
      
      5
      5
      5
      5
      5
      8
      8
      

      【數(shù)據(jù)范圍】\(M \le N, A \le 1 000 000\)

      【分析】滑動窗口裸題

      點(diǎn)擊查看代碼
      #include <bits/stdc++.h>
      using namespace std;
      typedef long long ll;
      const int N = 3e6 + 10, INF = 0x3f3f3f3f;
      int n, m, a[N], q[N];
      
      int main() {
          cin >> n >> m;
          for (int i = 1; i <= n; i++) cin >> a[i];
      
          int hh = 0, tt = -1;
          for (int i = 1; i <= n; i++) {
              while (hh <= tt && a[q[tt]] >= a[i]) tt--;
              while (hh <= tt && i - q[hh] + 1 > m) hh++;
              q[++tt] = i;
              if (i >= m) cout << a[q[hh]] << endl;
          }
          return 0;
      }
      

      課后練習(xí)

      P1739 表達(dá)式括號匹配

      【數(shù)據(jù)范圍】

      【分析】

      點(diǎn)擊查看代碼
      
      

      P1996 約瑟夫問題

      n 個(gè)人圍成一圈,從第一個(gè)人開始報(bào)數(shù),數(shù)到 m 的人出列,再由下一個(gè)人重新從 1 開始報(bào)數(shù),數(shù)到 m 的人再出圈,依次類推,直到所有的人都出圈,請輸出依次出圈人的編號。

      輸入格式:輸入兩個(gè)整數(shù) n,m(1≤m,n≤100)。
      輸出格式:輸出一行 n 個(gè)整數(shù),按順序輸出每個(gè)出圈人的編號。

      輸入樣例:10 3
      輸出樣例:3 6 9 2 7 1 8 5 10 4
      

      使用STL

      點(diǎn)擊查看代碼
      #include<bits/stdc++.h>
      using namespace std;
      queue<int> que;
      int main(){
          int n,m,cnt=1; cin>>n>>m;
          for(int i=1; i<=n; i++) que.push(i);
          while(!que.empty()){
              if(cnt<m){
                  que.push(que.front());
                  que.pop();  cnt++;
              }else if(cnt==m){
                  cout<<que.front()<<" ";
                  que.pop();  cnt=1;
              }
          } return 0;
      }
      

      P1808 單詞分類

      【題目描述】
      兩個(gè)單詞可以分為一類當(dāng)且僅當(dāng)組成這兩個(gè)單詞的各個(gè)字母的數(shù)量均相等。
      例如 "AABAC",它和 "CBAAA" 就可以歸為一類,而和 "AAABB" 就不是一類。
      現(xiàn)在Oliver有N個(gè)單詞,所有單詞均由大寫字母組成,每個(gè)單詞的長度不超過100。
      你要告訴Oliver這些單詞會被分成幾類。

      【輸入格式】輸入文件的第一行為單詞個(gè)數(shù)N,以下N行每行為一個(gè)單詞。
      【輸出格式】輸出文件僅包含一個(gè)數(shù),表示這N個(gè)單詞分成的類數(shù)

      輸入樣例 輸出樣例
      3
      AABAC
      CBAAA
      AAABB
      
      2
      
      點(diǎn)擊查看代碼
      #include<bits/stdc++.h>
      using namespace std;
      const int N=1e4+1;
      char s[N][101];
      int main(){
          int n; cin>>n;
          for(int i=1; i<=n; i++){
              scanf("%s", s[i]);
              sort(s[i], s[i]+strlen(s[i]));
          }
          map<string,int> m;
          for(int i=1; i<=n; i++){
              m.insert(pair<string,int>(s[i],1));
          }
          printf("%d", m.size());
          return 0;
      }
      

      B3616 【模板】隊(duì)列

      請你實(shí)現(xiàn)一個(gè)隊(duì)列(queue),支持如下操作:

      • push(x):向隊(duì)列中加入一個(gè)數(shù) \(x\)
      • pop():將隊(duì)首彈出。如果此時(shí)隊(duì)列為空,則不進(jìn)行彈出操作,并輸出 ERR_CANNOT_POP
      • query():輸出隊(duì)首元素。如果此時(shí)隊(duì)列為空,則輸出 ERR_CANNOT_QUERY
      • size():輸出此時(shí)隊(duì)列內(nèi)元素個(gè)數(shù)。

      輸入格式:第一行,一個(gè)整數(shù) \(n\),表示操作的次數(shù)。
      接下來 \(n\) 行,每行表示一個(gè)操作。格式如下:

      • 1 x,表示將元素 x 加入隊(duì)列。
      • 2,表示將隊(duì)首彈出隊(duì)列。
      • 3,表示查詢隊(duì)首。
      • 4,表示查詢隊(duì)列內(nèi)元素個(gè)數(shù)。

      輸出格式:輸出若干行,對于每個(gè)操作,按「題目描述」輸出結(jié)果。每條輸出之間應(yīng)當(dāng)用空行隔開。

      #include <bits/stdc++.h>
      using namespace std;
      const int N = 1e4 + 10;
      int que[N], head = 0, tol = 0;
      
      void push(int x) {
          que[tol++] = x;
      }
      void pop() {
          if (head == tol) cout << "ERR_CANNOT_POP" << endl;
          else ++head;
      }
      void query() {
          if (head >= tol) cout << "ERR_CANNOT_QUERY" << endl;
          else  cout << que[head] << endl;
      }
      int size() {
          return tol - head;
      }
      int main() {
          int n, op, x; cin >> n;
          while (n--) {
              cin >> op;
              switch (op) {
                  case 1: cin >> x, push(x); break;
                  case 2: pop(); break;
                  case 3: query(); break;
                  case 4: cout << size() << endl; break;
              }
          }
          return 0;
      }
      

      P3378 【模板】堆

      給定一個(gè)數(shù)列,初始為空,請支持下面三種操作:

      1. 給定一個(gè)整數(shù) x,請將 x 加入到數(shù)列中。
      2. 輸出數(shù)列中最小的數(shù)。
      3. 刪除數(shù)列中最小的數(shù)(如果有多個(gè)數(shù)最小,只刪除 1 個(gè))。

      輸入格式:第一行是一個(gè)整數(shù),表示操作的次數(shù) n。
      接下來 n 行,每行表示一次操作。每行首先有一個(gè)整數(shù) op 表示操作類型。
      若 op=1,則后面有一個(gè)整數(shù) x,表示要將 x 加入數(shù)列。
      若 op=2,則表示要求輸出數(shù)列中的最小數(shù)。
      若 op=3,則表示刪除數(shù)列中的最小數(shù)。如果有多個(gè)數(shù)最小,只刪除 1 個(gè)。
      輸出格式:對于每個(gè)操作 2,輸出一行一個(gè)整數(shù)表示答案。

      輸入樣例 輸出樣例
      5
      1 2
      1 5
      2
      3
      2
      
      2
      5
      

      【分析】

      點(diǎn)擊查看代碼
      #include<iostream>
      #include<queue>
      using namespace std;
      priority_queue<int, vector<int>, greater<int> > pq;
      //priority_queue<int, vector<int>, less<int> > pq;
      int main(){
          int n;  cin>>n;
          for(int i=1; i<=n; i++){
              int f; cin>>f;
              if(f==1){
                  int x;  cin>>x;  pq.push(x);
              }else if(f==2){
                  cout<<pq.top()<<endl;
              }else if(f==3){
                  pq.pop();
              }
          } return 0;
      }
      

      P4715 【深基16.例1】淘汰賽

      有 2^n(n≤7) 個(gè)國家參加世界杯決賽圈且進(jìn)入淘汰賽環(huán)節(jié)。
      我經(jīng)知道各個(gè)國家的能力值,且都不相等。能力值高的國家和能力值低的國家踢比賽時(shí)高者獲勝。
      1 號國家和 2 號國家踢一場比賽,勝者晉級。3 號國家和 4 號國家也踢一場,勝者晉級……晉級后的國家用相同的方法繼續(xù)完成賽程,直到?jīng)Q出冠軍。
      給出各個(gè)國家的能力值,請問亞軍是哪個(gè)國家?

      輸入樣例 輸出樣例
      3
      4 2 3 1 10 5 9 7
      
      1
      
      點(diǎn)擊查看代碼
      #include<iostream>
      #include<cmath>
      #include<queue>
      #include<map>
      using namespace std;
      int main() {
          int n; cin>>n; n = pow(2, n); // n=1<<n;
          queue<pair<int, int> > que;
          for(int i=1; i<=n; i++) {
              int a; cin>>a; que.push(make_pair(i, a));
          }
          while( que.size() > 2 ){
              pair<int, int> x,y;
              x = que.front(); que.pop();
              y = que.front(); que.pop();
              if(x.second > y.second) que.push(x);
              else que.push(y);
          }
          pair<int, int> x,y;
          x = que.front(); que.pop();
          y = que.front(); que.pop();
          if(x.second > y.second) cout<<y.first;
          else cout<<x.first;
          return 0;
      }
      
      posted @ 2024-08-13 08:05  HelloHeBin  閱讀(167)  評論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 成人中文在线| 国产绿帽在线视频看| 日产日韩亚洲欧美综合下载| 欧美野外伦姧在线观看| 国产一区二区不卡在线| 午夜大片免费男女爽爽影院| 亚洲精品亚洲人成人网 | 久久99国产精一区二区三区! | 综合色天天久久| 免费看黄色亚洲一区久久| 亚洲免费成人av一区| 日本亚洲一区二区精品久久| 乱女乱妇熟女熟妇综合网| 国产精品自拍视频第一页| 青铜峡市| 老司机免费的精品视频| 欧美成本人视频免费播放| 久久久久久久波多野结衣高潮| 国产精品亚洲一区二区三区| 蜜臀av黑人亚洲精品| 成人精品自拍视频免费看| 长腿校花无力呻吟娇喘| 国产不卡精品视频男人的天堂| 亚洲a∨国产av综合av下载| 人妻在线无码一区二区三区| 亚洲av永久无码精品水牛影视| 英德市| 亚洲成a人无码av波多野| 亚洲 校园 欧美 国产 另类| 久久毛片少妇高潮| 国产精品亚洲av三区色| 久久亚洲国产成人亚| 亚洲人成网站在线播放2019| 国产高清精品一区二区三区| 99久久亚洲精品无码毛片 | av新版天堂在线观看| 免费99精品国产人妻自在现线| 亚州中文字幕一区二区| 国产一区二区在线影院| 国产精品免费中文字幕| 人妻中文字幕精品系列|