首页 > 其他分享 >【题解】[NOIP2017 提高组] 逛公园

【题解】[NOIP2017 提高组] 逛公园

时间:2023-06-18 10:23:27浏览次数:40  
标签:NOIP2017 val int 题解 策策 逛公园 now dp dis

题目描述:

策策同学特别喜欢逛公园。公园可以看成一张 \(N\) 个点 \(M\) 条边构成的有向图,且没有 自环和重边。其中 \(1\) 号点是公园的入口,\(N\) 号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间。

策策每天都会去逛公园,他总是从 \(1\) 号点进去,从 \(N\) 号点出来。

策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间。如果 \(1\) 号点 到 \(N\) 号点的最短路长为 \(d\),那么策策只会喜欢长度不超过 \(d + K\) 的路线。

策策同学想知道总共有多少条满足条件的路线,你能帮帮它吗?

为避免输出过大,答案对 \(P\) 取模。

如果有无穷多条合法的路线,请输出 \(-1\)。

对于 \(100\%\) 的数据,\(N \le 10^5,M \le 2 \times 10^5\)

题目分析:

最短路计数显然可以想到 \(dp\),如果只是计数最短路的话显然,我们假设 \(dis[i]\) 表示到点 \(i\) 的最短路,就是直接设 \(dp[u]\) 表示到 \(u\) 且路径长度为 \(dis[u]\) 的路径条数。
那么这个题肯定需要多加一些维,看上去也就是只能把 \(k\) 扔进去了,也就是直接设 \(dp[u][i]\) 表示到 \(u\) 这个点路径长度为 \(dis[u] + i\) 的路径条数。
转移也是简单的:

\[\begin{aligned} &dp[u][dis[v] - dis[u] + i - (u,v)] \to dp[v][i] &(u,v) \in E \end{aligned} \]

然后就会发现这个转移顺序很难弄,所以就直接记忆化搜索就好了,以及无限解也就是 \(0\) 环的问题也要注意判一下。

代码:

点击查看代码
#include<bits/stdc++.h>
#define PII pair<int,int>
using namespace std;
const int N = 2e5+5;
int f[N][55],dis[N],n,m,k,MOD;
bool vis[N],ins[N][55],flag;
vector<PII> G1[N],G2[N];
void dij(){
	memset(dis,0x3f,sizeof(dis));memset(vis,false,sizeof(vis));
	dis[1] = 0;
	priority_queue<PII> q;
	q.push({-dis[1],1});
	while(!q.empty()){
		int now = q.top().second;q.pop();
		if(vis[now])	continue;
		vis[now] = true;
		for(PII p : G1[now]){
			int to = p.first,val = p.second;
			if(dis[to] > dis[now] + val){
				dis[to] = dis[now] + val;
				q.push({-dis[to],to});
			}
		}
	}
}
int dp(int now,int val){
	if(val < 0)	return 0;
	if(ins[now][val]){  //存在 0 环
		flag = true; 
		return 0;
	}
	if(f[now][val])	return f[now][val];
	ins[now][val] = true;
	int res = 0;
	for(auto p : G2[now]){
		int to = p.first,tmp = p.second;
		res = (res + dp(to,dis[now] - dis[to] + val - tmp))%MOD;
		if(flag)	return 0;
	}
	ins[now][val] = false;
	f[now][val] = res;
	return res;
}
int main(){
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	int T;scanf("%d",&T);
	while(T--){
		scanf("%d%d%d%d",&n,&m,&k,&MOD);
		for(int i=1; i<=m; i++){  //草,竟然写成了 n 
			int from,to,val;scanf("%d%d%d",&from,&to,&val);
			G1[from].push_back({to,val});
			G2[to].push_back({from,val});
		}
		dij();
		f[1][0] = 1;
		int ans = 0;
		for(int i=0; i<=k; i++){
//			printf("%d\n",dp(n,i));
			ans = (ans + dp(n,i))%MOD;
		}
		if(flag)	printf("-1\n");
		else	printf("%d\n",ans);
		memset(f,0,sizeof(f));memset(ins,0,sizeof(ins));flag = false;
		for(int i=1; i<=n; i++)	G1[i].clear(),G2[i].clear();
	}
	return 0;
}

标签:NOIP2017,val,int,题解,策策,逛公园,now,dp,dis
From: https://www.cnblogs.com/linyihdfj/p/17488760.html

相关文章

  • 【题解】Atcoder ABC300 F.More Holidays(线性做法)
    F.MoreHolidays题目描述:给你一个由o和x组成的长度为\(N\)的字符串\(S\),以及整数\(M\)和\(K\)。保证\(S\)至少包含一个x。假设\(T\)是由\(S\)复制\(M\)次而成的长度为\(NM\)的字符串。考虑将\(T\)中的\(K\)个x恰好替换为o。你的目标是在替换后的......
  • P2161 [SHOI2009]会场预约 题解
    蒟蒻提供一种fhq-treap的做法,但是不如其他题解的快(也没有stl快,不开O21.8s),但是比较好想,扩展了fhq的模板,也算是为使用fhq提供一个新方法。首先,fhq-treap是什么,如果有同学不清楚,请点击学习(并非我的blog)那么,由于fhq树的分裂操作,使得我们可以很方便的取出我们想要的区间。那么,在......
  • react经典面试题解析--持续更新--day01
    一、类组件和函数组件的区别(面试常考)简单理解(所有同学都要掌握)1、类组件有生命周期,函数组件没有2、类组件需要继承Class,函数组件不需要3、类组件可以获取实例化的this,并且基于this做各种操作,函数组件不行4、类组件内部可以定义并维护state,函数组件都称为无状态了,那肯定......
  • AtCoder ABC056D 题解
    题目直达0x00思路从大到小枚举每个元素,同时加入\(sum\)进行累计,当\(k\lesum\)时,便会返现之前的元素可以构成“好的组”(因为他们都大于\(p_i\)),即有用的,所以要清空。0x01举个例子36143我们对输入排序后,会得到\(p\)为。431这时,我们的\(i=1\),即\(p_i=......
  • AtCoder ABC228D 题解
    [ABC299D]FindbyQuery题解0x00题目分析题目传送门经过分析,我们得到的几个关键信息:\(n\le2\times10^5\)最多可以问法官\(20\)个问题。s[1]=0,s[n]=1分析\(n\)的范围,发现\(\log_n=17.6096\),刚好比\(20\)小一点点。这时便考虑二分的做法。看到s[1]=0,......
  • AtCoder ABC047D 题解
    题意理解&分析:大概的题意应该是十分清晰的,就是一个人要从\(1\)到\(n\)的城市中买苹果。另一个人要其中调整价格。这里的调整也不需要太多,就\(1\)就可以了。但是,如果有多组购买方案可以得到相同的利润,就还需要将其他相同的价格一并调整。这道题的关键就在于求出有几组购买......
  • CF1732D1 题解
    CF1732D1Balance题解题目解释输入一个\(op\)和\(x\),\(op\)有\(2\)种情况。\(op\)为+,则将\(x\)加入到集合中。\(op\)为?,则找到一个最小的\(k\),使\(k\timesx\)不在合集中。题目非常简单明了。具体实现这时,看到这句话:\(1\lex\le10^{18}\),所以不可......
  • 题解 CF1830C【Hyperregular Bracket Strings】
    卡特兰数一个长为\(2n\)的序列,填入括号,有多少种合法方案?\(C_n=\sum_iC_iC_{n-i-1}\),其中\(C_0=C_1=1\)。它的封闭形式是\(C_n=\binom{2n}{n}-\binom{2n}{n-1}\)。problem给定一个长度\(n\)和\(k\)个子区间\(\{[l1​,r1​],[l2​,r2​],…,[lk​,rk​]\}\)。问有多......
  • 【题解】CF754D Fedor and coupons(优先队列)
    【题解】CF754DFedorandcoupons题目链接CF754DFedorandcouponsCF1029CMaximalIntersection后者是前者的加强版。思路分析最开始,先考虑不删区间\((k=0)\)的情况:也就是给你一大堆区间,让你找他们的交集。这个还是比较好想的,我们刚开始让第二个区间与第一个区间相交......
  • 【CF1841C 题解】
    首先,我们把\(s\)翻转。考虑dp,\(f_{i,j,k}\)表示到了第\(i\)个字符,操作了\(j\)个字符,最大的字符为\(k\)的最大值。转移时枚举\(i-1\)的最大字符\(\ell(0\le\ell<5)\)。不操作第\(i\)个字符;\(f_{i,j,k}=\max\{f_{i-1,j,\ell}+w\}\)。操作第\(i\)......