HDU 6071 Lazy Running (最短路)
題目鏈接
http://acm.hdu.edu.cn/showproblem.php?pid=6071
題解
又是一道虐信心的智商題。。。
首先有一個輔助問題,這道題轉化了一波之后就會化成這個問題: 給定\(a_1,a_2,...,a_n\)和\(K\),求使得\(\sum^{n}_{i=1}a_ix_i=B\)有正整數解且\(B\ge K\)的最小\(B\)值。在本題中\(n=4, a_i\le 30000, K\le 10^{18}\).
這好像是個最短路經典問題,但是我想了三小時根本沒想到做法……
大概是隨便找一個\(a_k\)(一般來說找最小值節省常數)然后對于模\(a_k\)剩余系下每個數建一個點,每個數\(t\)向\((t+a_i)\mod a_k (k=1,2,...,n)\)連邊,這樣從\(1\)到\(j\)的最短路就是模\(a_k\)余\(j\)的最小\(B\). 這樣就可以在\(O(na_i\log n)\)的時間內解決上述問題。
下面我們把這個問題\(\{ a_i\} =\{ d_i\},K=x\)的答案記作\(f(x)\).
然后考慮原問題如何轉化為上述問題,我和題解的轉化方式不同。
下面是我的方法(我覺得沒啥問題,但是這題數據確實挺弱,有問題歡迎提出啊):
設\(d_1,d_2,d_3,d_4\)分別是\(1,2,3,4\)連向編號下一個的點的邊權,我們可以將從\(2\)點出發回到\(2\)點的路徑分為五種:
(1) 從\(2\)到\(1\)再回來,長度\(2d_1\).
(2) 從\(2\)到\(3\)再回來,長度\(2d_2\).
(3) 從\(2\)到\(3\)再到\(4\), 到\(1\)或者不到\(1\), 再回來。
此時\(d_2\)邊恰好經過往返各一次,\(d_3\)邊往返至少一次(防止出現不經過\(d_3\)直接去\(d_4\)的不合法情況),\(d_4\)邊往返次數任意,長度\(2d_2+2d_3+2k_3d_3+2k_4d_4\) (\(k_3,k_4\)為任意非負整數)
(4) 從\(2\)到\(1\)再到\(4\), 到\(3\)或者不到\(3\), 再回來。與上一種情況對稱,長度\(2d_1+2d_4+2k_3d_3+2k_4d_4\) (\(k_3,k_4\)為非負整數)
(5) 走一個環,環上的邊可以額外往返任意多次。長度\(d_1+d_2+d_3+d_4+k_1d_1+k_2d_2+k_3d_3+k_4d_4\) (\(k_1,k_2,k_3,k_4\)為非負整數)
現在考慮簡化以上討論:(3)和(4)各做一次與做兩次(5)等價,(5)做多于一次與做一次等價(因為做多次就相當于給\(k\)增加值),因此可以認為(5)至多做一次。
如果(1)(5), (2)(5)同時做都沒有意義,(1)(3), (2)(4)同時做相當于做了(5)也沒有意義。
考慮最優策略:
(1) 如果(5)做一次,那么(3)和(4)都沒有必要做了,因為(3)和(4)的操作就相當于給(5)中的\(k\)增加值。于是這一部分的答案就是\(f(n-d_1-d_2-d_3-d_4)+d_1+d_2+d_3+d_4\).
(2) 如果(5)不做,那么(3)和(4)中可以做一個,這一部分的答案是\(\min(f(n-2d_1-2d_4)+2d_1+2d_4,f(n-2d_2-2d_3)+2d_2+2d_3)\).
(3) 如果(3)(4)(5)都不做,那么考慮(1)和(2),這一部分應該是等于上述問題\(n=2, a_1=d_1,a_2=d_2,K=n\)時的答案。
時間復雜度\(O(d\log d)\), 詳細一點大概是\(ShortestPath(d,4d)+ShortestPath(d,2d)\).
這個樣寫可能唯一的好處就是常數比較小吧……
下面是題解的做法:
把剩余系的模數設為\(\min(d_1,d_2)\), 然后設\(f[i][j]\)表示在\(i\)這個點余數是\(j\)的答案,然后類似最短路轉移DP的方法來求。
時間復雜度\(O(d\log d)\), 詳細一點大概是\(ShortestPath(4d,8d)\).
代碼
#include<cstdio> #include<cstdlib> #include<iostream> #include<algorithm> #include<queue> #include<cstring> #define llong long long using namespace std;void read(int &x) {int f=1;x=0;char s=getchar();while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}x*=f; }const int N = 6e4; const int M = 1.2e5; const llong INF = 1000000000000200000ll; struct Edge {int v,nxt; llong w; } e[(M<<1)+3]; int fe[N+3]; struct DijNode {int u; llong x;DijNode() {}DijNode(int _u,llong _x) {u = _u,x = _x;}bool operator <(const DijNode &arg) const {return x>arg.x;} }; priority_queue<DijNode> pq; llong dis[N+3]; bool vis[N+3]; llong d[5],x; int n,en;void addedge(int u,int v,llong w) {en++; e[en].v = v; e[en].w = w;e[en].nxt = fe[u]; fe[u] = en; }void Dijkstra() {memset(dis,30,sizeof(dis)); memset(vis,0,sizeof(vis));dis[0] = 0ll; pq.push(DijNode(0,0ll));while(!pq.empty()){DijNode tmp = pq.top(); pq.pop(); int u = tmp.u;if(tmp.x!=dis[u]) continue;if(vis[u]) continue;vis[u] = true;for(int i=fe[u]; i; i=e[i].nxt){int v = e[i].v;if(dis[v]>dis[u]+e[i].w && vis[v]==false){dis[v] = dis[u]+e[i].w;pq.push(DijNode(v,dis[v]));}}} }void clear() {for(int i=0; i<=en; i++) e[i].v = e[i].w = e[i].nxt = 0;for(int i=0; i<=n; i++) fe[i] = 0;en = n = 0; }llong solve(llong x) {if(x<0) return 0ll;llong ret = x;while(dis[ret%n]>ret) ret++;return ret; }int main() {int T; scanf("%d",&T);while(T--){scanf("%lld%lld%lld%lld%lld",&x,&d[1],&d[2],&d[3],&d[4]);llong ans = INF,tmp;n = min(min(d[1]+d[1],d[2]+d[2]),min(d[3]+d[3],d[4]+d[4]));for(int i=0; i<n; i++){for(int j=1; j<=4; j++){addedge(i,(i+d[j]+d[j])%n,d[j]+d[j]);}}Dijkstra();tmp = solve(x-d[1]-d[2]-d[3]-d[4])+d[1]+d[2]+d[3]+d[4]; ans = min(ans,tmp);tmp = solve(x-d[1]-d[1]-d[4]-d[4])+d[1]+d[1]+d[4]+d[4]; ans = min(ans,tmp);tmp = solve(x-d[2]-d[2]-d[3]-d[3])+d[2]+d[2]+d[3]+d[3]; ans = min(ans,tmp);clear();n = min(d[1]+d[1],d[2]+d[2]);for(int i=0; i<n; i++){for(int j=1; j<=2; j++){addedge(i,(i+d[j]+d[j])%n,d[j]+d[j]);}}Dijkstra();tmp = solve(x); ans = min(ans,tmp);clear();printf("%lld\n",ans);}return 0; }總結
以上是生活随笔為你收集整理的HDU 6071 Lazy Running (最短路)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AtCoder AGC022C Rema
- 下一篇: HDU 6155 Subsequence