題解 LuoGu3953 逛公園

2021-09-29 06:23:03 字數 2086 閱讀 6907

原題傳送門

n oi

p2017tg

d1t3

noip2017tgd1t3

noip20

17tg

d1t3

當然是先跑個dij

kstr

adijkstra

dijkst

ra把最短路求出來

然後想到dp求答案

d pu

,d

dp_dp

u,d​

表示到u

uu路程為d

dd方案數

狀態太多,看到k

<=50

k<=50

k<=5

0更改狀態dpu

,d

dp_dp

u,d​

表示路程為dis

u+

ddis_u+d

disu​+

d的方案數(dis

udis_u

disu

​表示到u

uu的最短路)

然後用加法原理轉移

需要從最終態n

nn跑到最初態1

11所以跑反圖

直接拓撲上跑好像很麻煩,用記憶化dfs

dfsdf

s考慮一下-1的情況,就是0環的情況,開乙個fla

gu,d

flag_

flagu,

d​的陣列,如果重複到這個狀態兩遍就說明有0環

code:

#include

#define maxn 200010

#define maxm 51

using

namespace std;

struct node};

priority_queue q;

struct edgeedge[maxn <<1]

, edge2[maxn <<1]

;int num, num2, head[maxn]

, head2[maxn]

, dis[maxn]

, vis[maxn]

, flag[maxn]

[maxm]

, dp[maxn]

[maxm]

, n, m, k, p;

inline

intread()

void

addedge

(int x,

int y,

int z)

, head[x]

= num;

}void

addedge2

(int x,

int y,

int z)

, head2[x]

= num2;

}void

dijkstra()

);while

(!q.

empty()

));}

}}}int

dfs(

int u,

int l)

if(u ==1&&

!l)++sum;

dp[u]

[l]= sum;

flag[u]

[l]=0;

return sum;

}int

main()

dijkstra()

;memset

(dp,

255,

sizeof

(dp));

memset

(flag,0,

sizeof

(flag));

int ans =

0, flag =0;

for(

int i =

0; i <= k;

++i)

(ans +

= tmp)

%= p;}if

(!flag)

printf

("%lld\n"

, ans)

;else

puts

("-1");

}return0;

}

洛谷3953 逛公園(DP)

原題 這道題目看到k特別小,而且k n的空間不會gg,那麼我們考慮乙個dp對吧。設 dp i k 表示到了點i與最短路相差k值的方案數,然後直接記搜 不想用拓撲序列 就可以了。luogu judger enable o2 include include include include include...

洛谷P3953 逛公園

題目 題解 f u k 表示 dis u,n mindis u,n k的方案數,答案就是 f 1 k f u k f v k mindis v,n mindis u,n w 這樣怎麼判 0環呢?只要在搜尋的時候記錄個 instack 就 ok 了 如果當前的 v還在搜尋的棧中就可以直接返回 1了 不...

洛谷P3953 逛公園

發現 k leq 50 猜想時間複雜度肯定與 k 有關。令 dis x 表示 1 到 x 的最短路。考慮 dp。先不考慮無限解得情況,設 f x i 表示到達點 x 走過的路程長度為 dis x i 的方案數。那麼 f x i 肯定由一條邊 y,x 轉移而來。設 y,x 的長度為 d 則這條路徑到 ...