洛谷P3953 NOIp2017 逛公園

2021-08-11 00:28:01 字數 1858 閱讀 6814

考慮到邊權可能為

0 ,轉移的順序會影響最後的結果,因此我們用記憶化搜尋代替直接dp

0 環

如何判斷乙個點

u是否在滿足條件的路徑上?顯然我們可以知道這個點滿足di

s1[u

]+di

sn[u

]≤di

s1[n

]+k 我們把所有長度為

0 的邊建成乙個新圖,然後用ta

rjan

找出所有點數大於

1 的強連通分量(也就是

0環),逐個檢查上面的點即可

時間複雜度o(

mk)

#include 

#include

#include

#include

#include

using

namespace

std;

inline

int get()

const

int maxn = 0x3f3f3f3f;

const

int n = 1e5 + 5, m = n << 1;

int d1[n], dn[n], h[m], f[n][55], a[n];

int tm, n, m, k, p, ans, top, tis;

int dfn[n], low[n], stk[n];

bool vis[n], inv[n], flag;

struct edge

;edge p[m], *t = p, *lst[n];

edge q[m], *q = q, *rst[n];

inline

void linkedge(int x, int y, int z)

inline

void rinkedge(int x, int y, int z)

inline

void spfa(int src, int *dis)}}

}inline

void add(int &x, int y)

inline

int dfs(int x, int d)

return f[x][d];

}inline

void ckmin(int &x, int y)

inline

void tarjan(int x)

if (dfn[x] == low[x])

}int main()

spfa(1, d1); spfa(n, dn);

memset(dfn, 0, sizeof(dfn));

memset(inv, false, sizeof(inv)); flag = false;

for (int i = 1; i <= n; ++i)

if (!dfn[i]) tarjan(i);

if (flag)

for (int i = 1; i <= n; ++i)

for (edge *e = lst[i]; e; e = e->nxt)

e->cst += d1[i] - d1[e->to];

for (int k = 0; k <= k; ++k)

for (int i = 1; i <= n; ++i)

f[i][k] = -1;

ans = 0;

for (int k = 0; k <= k; ++k)

add(ans, dfs(1, k));

printf("%d\n", ans);

}// fclose(stdin); fclose(stdout);

return

0;}

洛谷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 則這條路徑到 ...

洛谷P3960 NOIP2017 列隊

資料結構題還是挺好玩的 注意到每次只變動三個點 x,y x,m n,m 其他地方都是整塊移動。可以開n 1個線段樹,前n個存每行前m 1個人,最後乙個存第m列的人。x,y 位置的人出列時,抽出該位置的標號,加到第n 1個線段樹的最後面去,抽出第n 1個線段樹的第x個元素 即 x,m 加到第x個線段樹...