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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【学习笔记】同余最短路

發布時間:2023/12/3 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【学习笔记】同余最短路 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

同余最短路是用來解決一類 ∑i=1naixi∈[L,R]\sum_{i=1}^n a_ix_i\in[L,R]i=1n?ai?xi?[L,R] 問題的方法。

其中 L,RL,RL,R 值非常大,而 nnn 不是很大,大概是接受 O(n2)O(n^2)O(n2) 的范圍,xix_ixi? 是自定義的系數。

先差分一下,變成 ∑i=1naixi∈[0,R]?∑i=1naixi∈[0,L?1]\sum_{i=1}^na_ix_i\in [0,R]-\sum_{i=1}^na_ix_i\in [0,L-1]i=1n?ai?xi?[0,R]?i=1n?ai?xi?[0,L?1]

我們選中其中 aia_iai? 最小的作為標準 a0a_0a0?。

顯然,每個數都能表示成 xa0+rxa_0+rxa0?+r 的形式,rrr 是余數 <a0<a_0<a0?。

然后我們將所有的數按照 rrr 分類,分出了 a0a_0a0? 個類,編號 0~a0?10\sim a_0-10a0??1。

考慮當我們能夠湊出一個數 t∈[L,R]t\in [L,R]t[L,R] 中,那么 t+a0,t+2a0,...t+a_0,t+2a_0,...t+a0?,t+2a0?,... 都能被湊出來。

且不難發現這些數都屬于一個余數類中。

如果我們能求出每個余數類中最小被表示出來的數 t0t_0t0?,那么就可以用 ?R?t0a0?+1\lfloor\frac{R-t_0}{a_0}\rfloor+1?a0?R?t0???+1 算出這個類中的 ∈[0,R]\in[0,R][0,R] 的合法數。

所以現在還需要快速求出每個類中的 t0t_0t0?

因為我們計算類中的個數就是無限制地用了 a0a_0a0?,所以不妨在這里就不再使用。即我們使用若干個除 a0a_0a0? 外的所有 aia_iai? 來構造出。

假設我們能構造出某個余數類中的數 ttt,那么我們就能構造出編號為 (t+ai)moda0(t+a_i)\mod a_0(t+ai?)moda0? 余數類中的數 t+ait+a_it+ai?

發現這個關系可以看作一條邊,而整個過程我們無非是在求到一個點(余數類)的最短路(最小能表示出的數)。

具體而言,將每個余數類建成一個點,然后點 xxx(x+ai)moda0(x+a_i)\mod a_0(x+ai?)moda0? 點連邊,邊權為 aia_iai?,然后求最短路。

000 點開始,初始化 dis(0)=0\text{dis}(0)=0dis(0)=0 即可。因為最小的可以被構造出來的數肯定是 000,什么數都不用即可。

跳樓機

luogu-P3403

注意:樓層是從 111 開始的。我們整體往下移動一個單位即可。這題還不用差分,雖然差分沒有任何難度。

#include <bits/stdc++.h> using namespace std; #define int long long #define Pair pair < int, int > vector < Pair > G[100005]; int h; int a[5], dis[100005]; priority_queue < Pair, vector < Pair >, greater < Pair > > q;void addedge( int u, int v, int w ) {G[u].push_back( make_pair( v, w ) ); }void dijkstra() {q.push( make_pair( dis[0] = 0, 0 ) );while( ! q.empty() ) {int u = q.top().second, w = q.top().first; q.pop();if( dis[u] ^ w ) continue;for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i].first; w = G[u][i].second;if( dis[v] > dis[u] + w )q.push( make_pair( dis[v] = dis[u] + w, v ) );}} }signed main() {scanf( "%lld", &h );for( int i = 1;i <= 3;i ++ ) scanf( "%lld", &a[i] );sort( a + 1, a + 4 );if( a[1] == 1 ) return ! printf("%lld\n", h );for( int i = 0;i < a[1];i ++ ) {addedge( i, ( i + a[2] ) % a[1], a[2] );addedge( i, ( i + a[3] ) % a[1], a[3] );}memset( dis, 0x3f, sizeof( dis ) );dijkstra();int ans = 0;for( int i = 0;i < a[1];i ++ )if( dis[i] <= h - 1 )ans += ( h - 1 - dis[i] ) / a[1] + 1;printf( "%lld\n", ans ); return 0; }

[國家集訓隊]墨墨的等式

luogu-P2371

#include <bits/stdc++.h> using namespace std; #define int long long #define Pair pair < int, int > int n, l, r; int dis[500005], a[15]; priority_queue < Pair, vector < Pair >, greater < Pair > > q; vector < Pair > G[500005];void addedge( int u, int v, int w ) {G[u].push_back( make_pair( v, w ) ); }void dijkstra() {q.push( make_pair( dis[0] = 0, 0 ) );while( ! q.empty() ) {int u = q.top().second, w = q.top().first; q.pop();if( dis[u] ^ w ) continue;for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i].first; w = G[u][i].second;if( dis[v] > dis[u] + w )q.push( make_pair( dis[v] = dis[u] + w, v ) );}} }int query( int n ) {int ans = 0;for( int i = 0;i < a[1];i ++ )if( dis[i] <= n )ans += ( n - dis[i] ) / a[1] + 1;return ans; }signed main() {scanf( "%lld %lld %lld", &n, &l, &r );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &a[i] );sort( a + 1, a + n + 1 );for( int i = 0;i < a[1];i ++ )for( int j = 2;j <= n;j ++ )addedge( i, ( i + a[j] ) % a[1], a[j] );memset( dis, 0x3f, sizeof( dis ) );dijkstra();printf( "%lld\n", query( r ) - query( l - 1 ) );return 0; }

總結

以上是生活随笔為你收集整理的【学习笔记】同余最短路的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。