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

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

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

      同余最短路的轉圈技巧

      Luogu

      眾所周知,在同余最短路算法中,我們選取基準物品的體積作為模數 \(m\),并對其它物品的體積 \(v_i\) 和所有 \(0\leq j < m\),從 \(j\)\((j + v_i)\bmod m\) 連權值為 \(v_i\) 的邊,跑最短路。

      算法介紹

      不要從圖論的角度考慮問題,而是回歸本源:體積模 \(m\) 意義下的完全背包。對于體積為 \(v_i\) 的物品,它在長度為 \(m\) 的環上形成 \(d = \gcd(v_i, m)\) 個子環。從一個點出發,不可能繞著子環走一圈再轉移回到該點,因為最短路不會經過同一個點兩次,否則存在負環。如果重復經過同一個點,那么可以將這兩次經過之間加入的所有物品替換為若干基準物品。

      因此,往背包加入體積為 \(v_i\) 的物品時,至多加入 \(\frac {m} {\gcd(v_i, m)} - 1\) 個。對于每一個子環,我們繞著這個環轉兩圈,即可考慮到所有轉移,因為每個點都轉移到了子環上其它所有點。時間復雜度 \(\mathcal{O}(nm)\)。

      對于普通的完全背包,即邊權等于 \(v_i\) 的問題,我們找到子環上權值最小的點,繞著環轉移一圈即可(daklqw)。但是寫起來不如轉兩圈簡潔。

      例題

      P2371 墨墨的等式

      以下是經典同余最短路問題「墨墨的等式」的轉圈代碼。它是普通的完全背包。

      #include <bits/stdc++.h>
      using namespace std;
      constexpr int N = 5e5 + 5;
      int n, m, a[N], _a[N];
      long long f[N], l, r, ans;
      int main() {
        cin >> n >> l >> r;
        for(int i = 1; i <= n; i++) {
          cin >> a[i];
          if(!a[i]) n--, i--;
        }
        if(!n) cout << "0\n", exit(0);
        memset(f, 0x3f, sizeof(f)), f[0] = 0;
        sort(a + 1, a + n + 1), m = a[1];
        for(int i = 1; i <= n; i++) _a[i] = a[i] % m; // 避免多次取模常數太大
        for(int i = 2; i <= n; i++) {
          for(int j = 0, lim = __gcd(a[i], m); j < lim; j++) {
            for(int t = j, c = 0; c < 2; c += t == j) {
              int p = t + _a[i];
              if(p >= m) p -= m;
              f[p] = min(f[p], f[t] + a[i]), t = p;
            }
          }
        }
        for(int i = 0; i < a[1]; i++) {
          if(r >= f[i]) ans += max(0ll, (r - f[i]) / a[1] + 1);
          if(l > f[i]) ans -= max(0ll, (l - 1 - f[i]) / a[1] + 1);
        }
        cout << ans << endl;
        return 0;
      }
      

      P9140 背包

      本題在完全背包的可行性基礎上加入了權值這一維度。

      如果我們將 \(\frac {c_i}{v_i}\) 最大的物品選做基準物品,設其體積為 \(m\),價值為 \(w\),那么同樣不會經過同一個點,原因是類似的:將一部分其它物品替換為若干基準物品,以最大化單位體積貢獻的價值。

      對于兩組背包方案 \((V_1, C_1)\)\((V_2, C_2)\),若 \(V_1\equiv V_2\pmod m\),該如何衡量這兩組方案的優劣呢?

      對于一組背包方案 \((V', C')\) 和一次查詢 \(V\),若 \(V'\equiv V\pmod m\)\(V' \leq V\),則其權值為 \(C' + \frac {V - V'} mw\)。因此,對于相同剩余系的所有背包方案 \((V', C')\),我們希望最大化 \(C' - \lfloor\frac {V'} {m}\rfloor w\),轉化為圖論就是最長路的 \(dist\)。也就是說,當加入物品 \((v_i, c_i)\)\(p\) 轉移到 \(q = (p + v_i)\bmod m\) 時,用于更新 \(f_q\) 的值為 \(f_p + c_i - \lfloor \frac {p + v_i} {m}\rfloor w\)。

      根據 \(\frac {w} {m}\) 的最大性,這樣一張包含正負權邊的圖上不存在正權環(求最長路)。又因為不經過重復點,所以每組剩余系的最優方案對應的 \(V'\) 不超過 \(m ^ 2\)\(10 ^ {10}\),配合 \(V\geq 10 ^ {11}\) 的限制保證了正確性。

      #include <bits/stdc++.h>
      using namespace std;
      using ll = long long;
      constexpr int N = 1e5 + 5;
      ll n, q, m = 1, w, V, f[N], c[55], v[55], _v[55], _d[55];
      int main() {
        ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
        cin >> n >> q;
        for(int i = 1; i <= n; i++) {
          cin >> v[i] >> c[i];
          if(w * v[i] < m * c[i]) w = c[i], m = v[i];
        }
        for(int i = 1; i <= n; i++) _v[i] = v[i] % m, _d[i] = v[i] / m; // 避免多次取模和除法常數太大
        for(int i = 1; i < m; i++) f[i] = -1e18;
        for(int i = 1; i <= n; i++) {
          for(int j = 0, lim = __gcd(v[i], m); j < lim; j++) {
            for(int t = j, _ = 0; _ < 2; _ += t == j) {
              int q = t + _v[i], d = _d[i];
              if(q >= m) q -= m, d++;
              f[q] = max(f[q], f[t] + c[i] - d * w), t = q;
            }
          }
        }
        for(int i = 1; i <= q; i++) {
          cin >> V;
          int p = V % m;
          if(f[p] < -1e17) cout << "-1\n";
          else cout << f[p] + V / m * w << "\n";
        }
        return 0;
      }
      

      和其它算法的對比

      SPFA 跑同余最短路的復雜度依然是個謎。它的理論上界是 \(\mathcal{O}(|V||E|)\)\(\mathcal{O}(nm ^ 2)\),但實際表現和小常數 \(\mathcal{O}(nm)\) 同樣優秀。

      此外,在可以使用最大體積作為基準元素時,令 \(f_i\) 除以 \(m\) 下取整得 \(f'_i\),則 \(f_i = f'_i m + i\)。對于 \(f'\),邊權只有 \(0\)\(1\),01-BFS(FZzzz)。

      顯然,轉圈技巧比最短路好寫,且適用范圍沒有任何限制,如 01-BFS 就無法解決第二道例題。

      總結

      同余最短路的本質是根據單調性值域定義域互換后將完全背包轉化為體積模 \(m\) 意義下的完全背包。普通完全背包的轉移是有向無環圖,而體積模 \(m\) 的完全背包的轉移成環,這讓我們想到最短路。最短路不成環,對應原問題就是可以將兩次經過同一個點之間添加的所有物品換成若干基準物品。所以,我們可以將完全背包轉化為類多重背包問題。

      筆者在研究「背包」一題的官方解法時,驚訝于其 “轉兩圈” 思想的巧妙。翻了一遍經典同余最短路題目,也沒找到幾篇除了 SPFA 和 Dijkstra 以外的題解,故分享給各位讀者。

      同余最短路還在寫最短路?時代的眼淚!

      posted @ 2023-07-06 10:38  qAlex_Weiq  閱讀(4278)  評論(3)    收藏  舉報
      主站蜘蛛池模板: 亚洲av成人一区在线| 色爱综合激情五月激情| 激情综合网激情五月伊人| 日韩永久永久永久黄色大片| 4hu四虎永久在线观看| 精品无码黑人又粗又大又长| 99国精品午夜福利视频不卡99| 九九久久人妻精品一区色| 国产一区二区不卡视频在线| 亚洲爆乳少妇无码激情| 一个人在线观看免费中文www| 天天澡日日澡狠狠欧美老妇| 99久久国产综合精品色| 午夜无码国产18禁| 蜜桃久久精品成人无码av| 中文字幕熟妇人妻在线视频| 中文字幕无线码免费人妻| 少妇高潮喷潮久久久影院| 国产av不卡一区二区| 欲色欲色天天天www| 日韩一区二区黄色一级片| 国产日产亚洲系列av| 亚洲嫩模一区二区三区 | 久久人人97超碰人人澡爱香蕉| gogogo高清在线观看视频中文| 通化市| 绿春县| 日本一区二区精品色超碰| 综合激情亚洲丁香社区| 西乡县| 久久国产成人午夜av影院| 五月天免费中文字幕av| 亚洲色拍拍噜噜噜最新网站 | 最近高清中文在线字幕在线观看| 久久精品不卡一区二区| 日韩无人区码卡1卡2卡| 又黄又刺激又黄又舒服| 精品国产一区二区三区av色诱| 人妻精品动漫H无码中字| 7m精品福利视频导航| 午夜丰满少妇性开放视频|