Luogu3953:逛公园

这题看上去想拿分层图做啊

f[x][k] 表示 到节点 x 走过的路程为 k + x的最短路 的方案数

然而只有六十分,因为判 0 环太暴力了 //好像应该有 70 ?

于是颓题解的记搜 //分层图的判 0 环似乎不是很可写

就大力搜索大力记忆化啊

判 0 环很神奇,不过跟两遍 spfa 的思路是差不多的,因为最短路树上不会去经过正权环

所以有环一定是 0 环

枚举到点 n 的距离和点 n 的最短路的差,倒着往回搜看会不会搜会当前状态,搜回来了就说明有 0 环

否则统计答案


代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<cstdio>
#include<queue>
using namespace std;

typedef long long ll;
const int MAXN = 100005, MAXM = 200005;

struct EDGE{
	int nxt, to, val;
	EDGE(int NXT = 0, int TO = 0, int VAL = 0) {nxt = NXT; to = TO; val = VAL;}
}edge[MAXM << 1];
int t, n, m, k, totedge;
int head[MAXN][2], dst[MAXN], vis[MAXN][55];
ll p, f[MAXN][55], ans;
bool vs[MAXN], ins[MAXN][55], fns[MAXN][55], GG;
priority_queue<pair<int,int> > q1;

inline int rd() {
	register int x = 0;
	register char c = getchar();
	while(!isdigit(c)) c = getchar();
	while(isdigit(c)) {
		x = x * 10 + (c ^ 48);
		c = getchar();
	}
	return x;
}
inline void add(int x, int y, int v, int rev) {
	edge[++totedge] = EDGE(head[x][rev], y, v);
	head[x][rev] = totedge;
	return;
}
inline void dij() {
	dst[1] = 0;
	q1.push(make_pair(0, 1));
	while(!q1.empty()) {
		int x = q1.top().second; q1.pop();
		if(vs[x]) continue;
		vs[x] = true;
		for(int i = head[x][0]; i; i = edge[i].nxt) {
			int y = edge[i].to;
			if(dst[y] > dst[x] + edge[i].val) {
				dst[y] = dst[x] + edge[i].val;
				q1.push(make_pair(-dst[y], y));
			}
		}
	}
	ans = 0ll;
	return;
}
int dfs(int x, int dlt) {
	if(ins[x][dlt]) {
		GG = true;
		return f[x][dlt] = -1;
	}
	if(fns[x][dlt]) return f[x][dlt];
	ins[x][dlt] = true;
	for(int i = head[x][1]; i; i = edge[i].nxt) {
		int y = edge[i].to, dlty = dst[x] + dlt - edge[i].val - dst[y];
		if(0 <= dlty && dlty <= k) f[x][dlt] = (f[x][dlt] + dfs(y, dlty)) % p;
	}
	fns[x][dlt] = true;
	ins[x][dlt] = false;
	return f[x][dlt];
}
inline void clearall() {
	totedge = 0; GG = false;
	for(int i = 1; i <= n; ++i) {
		head[i][0] = head[i][1] = 0;
		vs[i] = false;
		for(int j = 0; j <= 50; ++j) {
			f[i][j] = 0ll;
			fns[i][j] = ins[i][j] = false;
			vis[i][j] = 0;
		}
	}
	return;
}

int main() {
	t = rd();
	while(t--) {
		n = rd(); m = rd(); k = rd(); p = (ll)rd();
		register int xx, yy, vv;
		for(int i = 1; i <= m; ++i) {
			xx = rd(); yy = rd(); vv = rd();
			add(xx, yy, vv, 0); add(yy, xx, vv, 1);
		}
		for(int i = 1; i <= n; ++i) dst[i] = 0x3f3f3f3f;
		dij();
		f[1][0] = 1ll;
		for(int i = 0; i <= k; ++i) ans = (ans + dfs(n, i)) % p;
		printf("%lld\n", GG ? -1 : ans);
		clearall();
	}
	return 0;
}

  

 

posted @ 2018-09-04 10:59  EvalonXing  阅读(114)  评论(0编辑  收藏  举报