• 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
    ", GG ? -1 : ans);
    		clearall();
    	}
    	return 0;
    }
    

      

    禁止诸如开发者知识库/布布扣/码迷/学步园/马开东等 copy 他人博文乃至博客的网站转载 ,用户转载请注明出处:https://www.cnblogs.com/xcysblog/
  • 相关阅读:
    startActivityForResult()的用法(转)
    计算机的特点
    Pinyin4j的基本用法
    简述Asp.net中断点续传的原理与实现
    ACE自适配通信环境简介
    如何将sql查询结果(不止一项)插入到一张表中
    CShell简介
    解析自定义时间格式字符串
    彻底删除IE核心浏览器的右键菜单残留项
    ACE线程管理机制
  • 原文地址:https://www.cnblogs.com/xcysblog/p/9583206.html
Copyright © 2020-2023  润新知