【傻逼】wxr

看到 \(k=50\),考虑按路径长度为一维度 dp。

\(f_{u,k}\) 为 从 \(1\)\(u\) 路径长度为 \(d_u+k\) 的总方案数。

需要以倒拓扑序的顺序进行转移。

对于图上的每条边 \(e(u,v)\),有转移方程:

\(f_{u,k}=\sum\limits_{e(u,v)}f_{v,k-(d_u + w - d_v)} \ (d_u+w-d_v<k)\)

其中 \(d_u+w_{u,v}-d_v\) 为较 \(d_v\) 经过 \(e(u,v)\) 多走的路程。

考虑按路径长度进行记忆化搜索求解。

具体实现可以建反图后搜索。

注:在搜索过程中如果遇见 \(0\) 环,则存在无穷种路径,输出 \(-1\)。可以通过维护每个点在当前路径长度被搜索到的次数判环。

代码没写。主要是不会。

写了。

#include <bits/stdc++.h>
typedef long long ll;
const int maxn = 2e6 + 20;
const int maxm = 4e6 + 20;
const int maxk = 55;
const ll inf = 4e18;
ll dis[maxn];
bool mk[maxn];
int n, m, k, mod;
ll f[maxn][maxk]; 
int vis[maxn][maxk];
ll ans = 0;
bool inLoop;
struct Graph {
	struct edge { int u, v, w, next; } e[maxn];
	int head[maxn], idx;
	void add(int x, int y, int z){
		idx++; e[idx].u = x, e[idx].v = y, e[idx].w = z;
		e[idx].next = head[x], head[x] = idx;
	}
	void clear() { memset(head, 0, sizeof head); idx = 0; }
} G, revG;
struct point{
	int u; ll dis;
	friend bool operator < (point a, point b){
		return a.dis > b.dis;
	}
	point(int a, ll b){
		u = a, dis = b;
	}
};
void dijkstra(int st, Graph &G){
	std::priority_queue<point> q; 
	dis[st] = 0; q.push(point(st, 0));
	while(!q.empty()){
		int u = q.top().u; q.pop();
		if(mk[u]) continue;
		mk[u] = 1;
		for(int i = G.head[u]; i; i = G.e[i].next){
			int v = G.e[i].v, w = G.e[i].w;
			if(dis[v] > dis[u] + w){
				dis[v] = dis[u] + w;
				q.push(point(v, dis[v]));
			}
		}
	}
}
int dfs(int u, int dk, Graph &G) {
	if(dk < 0 || dk > k) return 0;
	if(f[u][dk] != -1) return f[u][dk];
	f[u][dk] = 0, vis[u][dk] = 1;
	for(int i = G.head[u]; i; i = G.e[i].next) {
		int v = G.e[i].v, w = G.e[i].w, len = dk - (dis[v] + w - dis[u]);
		if(len < 0 || len > k) continue;
		if(vis[v][len]) { inLoop = 1; return 0; }
		f[u][dk] += dfs(v, len, G);
		if(f[u][dk] >= mod) f[u][dk] -= mod;
	}
	vis[u][dk] = 0;
	return f[u][dk];
}
void init() {
	ans = 0, inLoop = 0;
	G.clear(), revG.clear();
	for(int i = 0; i <= n + 1; i++)
		for(int j = 0; j <= k; j++)
			f[i][j] = -1, vis[i][j] = 0;
	for(int i = 1; i <= n + 1; i++) dis[i] = inf, mk[i] = 0;
}
void solve() {
	scanf("%d %d %d %d", &n, &m, &k, &mod);
	init();
	for(int i = 1; i <= m; i++){
		int x, y, z;
		scanf("%d %d %d", &x, &y, &z);
		G.add(x, y, z), revG.add(y, x, z);
	}
	G.add(n + 1, 1, 0), revG.add(1, n + 1, 0);
	dijkstra(n + 1, G);
	f[n + 1][0] = 1;
	for(int i = 0; i <= k; i++) {
		ans += dfs(n, i, revG);
		if(ans >= mod) ans -= mod;
	}
	printf("%lld\n", inLoop ? -1 : ans);
}
int main(){
	int t; scanf("%d", &t);
	while(t--) solve();
	return 0;
}
posted @ 2023-12-26 20:57  CQWDX  阅读(84)  评论(1编辑  收藏  举报