其实是参考洛谷上某篇题解的思路;

先求出两个dis数组表示从1走和从n走的最短路;

转移方程:dp[v][dis1[u]-dis1[v]+w+j]+=dp[u][j];

转移顺序要注意一下呢,肯定是先枚举第二维;

dis1[u]-dis1[v]+w+j>=j;

因为有等号,即有同层之间的转移,第一维也不能随便枚举;

如果没有0边,我们可以考虑按dis1从小到大枚举,和dijkstra很像,可以保证更新顺序是对的;

有了零边就要考虑连续好几个零边之间的转移,这个可以把0边挑出来拓扑排序;

关于-1的判断,把零边挑出来之后是可以知道那些点是在零环中的,再看一下经过这个点的路径有没有满足条件的就好了。

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn=;
const ll inf=1e12;
ll dp[maxn][],dis[maxn][];
struct edg{
int nex,to;
ll w;
}e[maxn*][];
struct node{
int id;
ll dis;
bool operator<(const node&a)const{
return dis>a.dis;
}
}A,B;
int s,flag,head,tail,t1,t2,vis[maxn],last[maxn][],T,n,m,k,p,x,y,qq[maxn];
int h[maxn],pre[maxn*],other[maxn*],t3,du[maxn],tot,in[maxn];
ll z;
priority_queue<node>q;
void add3(int x,int y){++t3;pre[t3]=h[x];h[x]=t3;other[t3]=y;}
void add1(int x,int y,ll z){++t1;e[t1][].nex=last[x][];last[x][]=t1;e[t1][].to=y;e[t1][].w=z;}
void add2(int x,int y,ll z){++t2;e[t2][].nex=last[x][];last[x][]=t2;e[t2][].to=y;e[t2][].w=z;}
void dijkstra(int lei){
//lei=0,1为起点,lei=1,n为起点;
while(!q.empty())q.pop();
memset(vis,,sizeof(vis));
for(int i=;i<=n;++i)dis[i][lei]=inf;
if(!lei)s=;else s=n;
dis[s][lei]=;
A.id=s;A.dis=;q.push(A);
while(!q.empty()){
B=q.top();q.pop();
if(vis[B.id])continue;
vis[B.id]=;
for(int i=last[B.id][lei];i;i=e[i][lei].nex){
int v=e[i][lei].to;
if(vis[v])continue;
if(dis[v][lei]>dis[B.id][lei]+e[i][lei].w){
dis[v][lei]=dis[B.id][lei]+e[i][lei].w;
A.id=v;A.dis=dis[v][lei];
q.push(A);
}
}
}
}
struct hehe{
ll dis;
int id,u;
bool operator<(const hehe&a)const{
if(dis==a.dis)return id<a.id;
return dis<a.dis;
}
}lj[maxn];
void tp(){
for(int i=;i<=n;++i){
lj[i].dis=inf;
lj[i].id=;
}
flag=;
head=tail=;
for(int i=;i<=n;++i)if(in[i]&&!du[i]){
qq[++tail]=i;lj[i].id=tail;
}
while(head<tail){
int u=qq[++head];
for(int i=h[u];i;i=pre[i]){
int v=other[i];
du[v]--;
if(!du[v]){qq[++tail]=v;lj[v].id=tail;}
}
}
for(int i=;i<=n;++i){
if(in[i]&&du[i]){
if(dis[i][]+dis[i][]<=dis[n][]+k){
flag=;
}
}
}
}
int main(){
cin>>T;
while(T--){
scanf("%d%d%d%d",&n,&m,&k,&p);
t1=t2=t3=;
memset(last,,sizeof(last));
memset(du,,sizeof(du));
memset(in,,sizeof(in));
memset(dp,,sizeof(dp));
memset(h,,sizeof(h));
for(int i=;i<=m;++i){
scanf("%d%d%lld",&x,&y,&z);
add1(x,y,z);add2(y,x,z);
if(!z){add3(x,y);du[y]++;in[x]=in[y]=;}
}
dijkstra();
dijkstra();
tp();
if(!flag){puts("-1");continue;}
else{
for(int i=;i<=n;++i){
lj[i].dis=dis[i][];
lj[i].u=i;
}
sort(lj+,lj+n+);
dp[][]=;
for(int j=;j<=k;++j)
for(int i=;i<=n;++i)
{
int u=lj[i].u;
for(int l=last[u][];l;l=e[l][].nex){
int v=e[l][].to;
if(dis[u][]-dis[v][]+e[l][].w+j<=k){
dp[v][dis[u][]-dis[v][]+e[l][].w+j]+=dp[u][j];
if(dp[v][dis[u][]-dis[v][]+e[l][].w+j]>=p)dp[v][dis[u][]-dis[v][]+e[l][].w+j]-=p;
}
}
}
ll ans=;
for(int i=;i<=k;++i){
ans+=dp[n][i];
if(ans>=p)ans-=p;
}
printf("%lld\n",ans);
}
}
//system("pause");
return ;
}

代码

noip2017d1t3的更多相关文章

  1. 并不对劲的noip2017d1t3

    因为A掉了d1t1,十分开心,把d1t3的代码调出来了. 一般情况下,noip每一天总有一道dp题,然而d1前两道题都不是,再看看第三题的数据范围,就能大概猜出是dp了. 这道题和最短路计数看上去很像 ...

  2. noip2017D1T3逛公园(拓扑图上dp,记忆化搜索)

    QWQ前几天才刚刚把这个D1T3写完 看着题解理解了很久,果然我还是太菜了QAQ 题目大意就是 给你一个n个点,m条边的图,保证1能到达n,求从1到n的 (设1到n的最短路长度是d)路径长度在[d,d ...

  3. 洛谷P3953逛公园

    题目 作为\(NOIp2017D1T3\) 这个题还是很良心的,至少相对于\(NOIp2018\)来说,希望\(NOIp2019\)不会这么坑吧. 这个题可以作为记忆化搜索的进阶题了,做这个题的方法也 ...

随机推荐

  1. 线程 day40

    操作系统线程理论 线程概念的引入背景 进程 之前我们已经了解了操作系统中进程的概念,程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程.程序和进程的区别 ...

  2. Spring Boot 2.0(一):Spring Boot 2.0尝鲜-动态 Banner

    Spring Boot 2.0 提供了很多新特性,其中就有一个小彩蛋:动态 Banner,今天我们就先拿这个来尝尝鲜 Spring Boot 更换 Banner 我们先来回顾一下在 Spring Bo ...

  3. hdu 4004 (二分加贪心) 青蛙过河

    题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4004 题目意思是青蛙要过河,现在给你河的宽度,河中石头的个数(青蛙要从石头上跳过河,这些石头都是在垂 ...

  4. spring读取properties的几种方式

    参考链接:http://www.cnblogs.com/zxf330301/p/6184139.html

  5. 爬取掌阅app免费电子书数据

    主要介绍如何抓取app数据及抓包工具的使用,能看到这相信你已经有爬虫基础了 编不下去了,主要是我懒,直接开干吧! 一.使用环境和工具 windows + python3 + Jsonpath + Ch ...

  6. 网页定时器setTimeout( )

    不斷重複執行的 setTimeout( ) setTimeout( ) 預設只是執行一次, 但我們可以使用一個循環方式, 使到一個setTimeout( ) 再啟動自己一次, 就會使到第二個 setT ...

  7. linux日志查找技巧

    1.查找日志最后10行 tail -n test.log 查询日志尾部最后10行的日志; 2.关键词查询 grep '2014-12-17 16:17:20' test.log

  8. insert执行错误,怎么样获取具体的错误原因

    1.开启debug 2.去runtime里面去找最后执行的SQL

  9. spring Springmvc mybatis maven整合

    一.准备工作 1. 首先创建一个表: CREATE TABLE `t_user` ( `USER_ID` int(11) NOT NULL AUTO_INCREMENT, `USER_NAME` ch ...

  10. 基于内存,redis,mysql的高速游戏数据服务器设计架构 ZT

    zt  http://www.cnblogs.com/captainl1993/p/4788236.html 1.数据服务器详细设计 数据服务器在设计上采用三个层次的数据同步,实现玩家数据的高速获取和 ...