因为A掉了d1t1,十分开心,把d1t3的代码调出来了。

一般情况下,noip每一天总有一道dp题,然而d1前两道题都不是,再看看第三题的数据范围,就能大概猜出是dp了。

这道题和最短路计数看上去很像。回想一下最短路计数的解法,大概是按照bfs序进行dp,dp[u]表示到节点u的条数。对于这道题而言,求的不是最短路条数而是长度不超过最短路+k的路径条数,那么就可以用dp[u][j]表示到节点u路径长度等于j的路径数。

至于如何转移,用dis[x]表示x到1的最短路长度,则当dis[u]+w[k]+j-dis[x]<=k有dp[x][dis[u]+w[k]+j-dis[vv]]+=dp[u][j]。

至于转移顺序,想到最短路计数是bfs序,而这道题有边权,那么就是dijkstra序(<-瞎编的词),其实就是dis[x]由小到大的顺序。

至于0边,需要建一个新图,图中只有0边。用一个拓扑排序找出0环,若环上存在点x满足1到x的距离+x到n的距离<=1到n的距离+k,则这个环会被计数,输出-1。还有一点需要注意的是,当出现0边时,dp顺序不单单是dis[x]的顺序。当出现x--0-->y,显然是要先算dp[x]的。这是就需要用到之前算出的拓扑序,当两个点的dis相等时,先算拓扑序靠前的那个。

下面是代码,我略作修改,使它有可能RE。

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define stnd struct node
#define nd node
#define oops operator
#define maxn 400010
#define maxm 800010
#define ll long long
using namespace std;
ll v[maxm],w[maxm],fir[maxn],nxt[maxm],cnt;//For roads.
ll fv[maxm],fw[maxm],ffir[maxn],fnxt[maxm],fcnt;//For froads.
ll tl,in[maxn],dep[maxn],ord[maxn],inq[maxn];//For topo sorting.
ll n,m,inf,t,dp[maxn][],kkk,p;;//For counting.
ll dis[maxn],fdis[maxn];//For dijkstra.
bool fl,vis[maxn][];
stnd
{
ll x,y;
bool oops <(const nd &zz)const
{
return y>zz.y;
}
};
inline ll read()
{
ll xx=,ff=;
char ch=getchar();
while(isdigit(ch)== && ch!='-')ch=getchar();
if(ch=='-')ff=-,ch=getchar();
while(isdigit(ch))xx=xx*+ch-'',ch=getchar();
return xx*ff;
}
void addedge(ll u1,ll v1,ll w1)
{
v[cnt]=v1,w[cnt]=w1,nxt[cnt]=fir[u1],fir[u1]=cnt++;
fv[fcnt]=u1,fw[fcnt]=w1,fnxt[fcnt]=ffir[v1],ffir[v1]=fcnt++;
}
void dj()
{
memset(dis,0x7f,sizeof(dis));
priority_queue<stnd>q;
stnd tmp;
tmp.x=,tmp.y=;
dis[]=;
q.push(tmp);
while(!q.empty())
{
ll u=q.top().x,du=q.top().y;q.pop();
if(dis[u]<du)continue;
for(ll k=fir[u];k!=-;k=nxt[k])
{
ll vv=v[k];
if(dis[vv]>dis[u]+w[k])
{
dis[vv]=dis[u]+w[k];
tmp.x=vv,tmp.y=dis[vv];
q.push(tmp);
}
}
}
}
void fdj()
{
memset(fdis,0x7f,sizeof(fdis));
priority_queue<stnd>q;
stnd tmp;
tmp.x=n,tmp.y=;
fdis[n]=;
q.push(tmp);
while(!q.empty())
{
ll u=q.top().x,du=q.top().y;q.pop();
if(fdis[u]<du)continue;
for(ll k=ffir[u];k!=-;k=fnxt[k])
{
ll vv=fv[k];
if(fdis[vv]>fdis[u]+fw[k])
{
fdis[vv]=fdis[u]+fw[k];
tmp.x=vv,tmp.y=fdis[vv];
q.push(tmp);
}
}
}
}
void topoo(ll xx)
{
inq[xx]=;
ord[tl++]=xx;
for(ll k=fir[xx];k!=-;k=nxt[k])
{
if(w[k]!=)continue;
ll vv=v[k];
in[vv]--;
if(in[vv]==)
topoo(vv);
}
return;
}
void topo()
{
tl=;
memset(inq,,sizeof(inq));
memset(in,,sizeof(in));
for(ll i=;i<m;i++)
if(w[i]==)in[v[i]]++;
for(ll i=;i<=n;i++)
if(inq[i]== && in[i]==)
topoo(i);
for(ll i=;i<=n;i++)
{
if(in[i]!= &&
dis[i]+fdis[i]<=dis[n]+kkk)
fl=;
}
}
bool dfs(int u,int j)
{
if(vis[u][j])return ;
if(~dp[u][j])return ;
vis[u][j]=;
if(u==n)dp[u][j]=;
else dp[u][j]=;
for(int k=fir[u];k!=-;k=nxt[k])
{
int vv=v[k],tt=dis[u]-dis[vv]+w[k]+j;
if(tt<=kkk &&
dis[u]+j+w[k]+fdis[vv]<=kkk+fdis[])
{
if(dfs(vv,tt))return ;
dp[u][j]+=dp[vv][tt];
dp[u][j]%=p;
}
}
vis[u][j]=;
return ;
}
int main()
{
t=read();
while(t--)
{
cnt=fcnt=fl=;
n=read(),m=read(),kkk=read(),p=read();
memset(fir,-,sizeof(fir));
memset(ffir,-,sizeof(ffir));
memset(dp,-,sizeof(dp));
memset(vis,,sizeof(vis));
for(ll i=;i<=m;i++)
{
ll x=read(),y=read(),z=read();
addedge(x,y,z);
}
dj();
fdj();
topo();
if(fl)cout<<-;
else
{
dfs(,);
cout<<dp[][];
}
cout<<endl;
}
return ;
}

并不对劲的noip2017d1t3的更多相关文章

  1. 并不对劲的BJOI2019

    一些感想 现实并非游戏,并不支持反复刷关 猎人和防御工事一起被老山龙摧毁了: 猎人惨死雨中,结云村永无放晴之日: 猎人被狂龙病毒侵蚀,天空山上黑蚀龙泛滥. 好像这才是怪物猎人系列的真实结局呢 day ...

  2. 并不对劲的uoj276. [清华集训2016]汽水

    想要很对劲的讲解,请点击这里 题目大意 有一棵\(n\)(\(n\leq 50000\))个节点的树,有边权 求一条路径使该路径的边权平均值最接近给出的一个数\(k\) 输出边权平均值下取整的整数部分 ...

  3. 并不对劲的DFT

    FFT是一个很多人选择背诵全文的算法. #include<algorithm> #include<cmath> #include<complex> #include ...

  4. 并不对劲的字符串专题(三):Trie树

    据说这些并不对劲的内容是<信息学奥赛一本通提高篇>的配套练习. 并不会讲Trie树. 1.poj1056-> 模板题. 2.bzoj1212-> 设dp[i]表示T长度为i的前 ...

  5. 并不对劲的字符串专题(二):kmp

    据说这些并不对劲的内容是<信息学奥赛一本通提高篇>的配套练习. 先感叹一句<信息学奥赛一本通提高篇>上对kmp的解释和matrix67的博客相似度99%(还抄错了),莫非mat ...

  6. 并不对劲的bzoj1861: [Zjoi2006]Book 书架

    传送门-> 这题的正确做法是splay维护这摞书. 但是并不对劲的人选择了暴力(皮这一下很开心). #include<algorithm> #include<cmath> ...

  7. 并不对劲的bzoj3932: [CQOI2015]任务查询系统

    传送门-> 离线操作听上去很简单,遗憾的是它强制在线. 每个时刻可以看成可持久化线段树中的一个版本,而每一个版本的线段树维护的是值某一段区间且在这个版本对应的时刻出现的数之和. 会发现同一时刻可 ...

  8. 并不对劲的bzoj1853:[SCOI2010]幸运数字

    传送门-> 据说本题的正确读法是[shìng运数字]. 听上去本题很适合暴力,于是并不对劲的人就去写了.其实这题就是一个很普(有)通(趣)暴力+神奇的优化. 首先,会发现幸运数字很少,那么就先搜 ...

  9. 并不对劲的bzoj4199: [Noi2015]品酒大会

    传送门-> 又称普及大会. 这题没什么好说的……后缀自动机裸题……并不对劲的人太菜了,之前照着标程逐行比对才过了这道题,前几天刚刚把这题一遍写对…… 这题的输出和某两点相同后缀的长度有关,那么把 ...

随机推荐

  1. 机器学习基础-Logistic回归1

    利用Logistic回归进行分类的主要思想是:根据现有数据对分类边界线建立回归公式,以此进行分类. 训练分类器时的做法就是寻找最佳拟合参数,使用的时最优化算法. 优点:计算代价不高,利于理解和实现. ...

  2. [BZOJ4052][Cerc2013]Magical GCD

    [BZOJ4052][Cerc2013]Magical GCD 试题描述 给出一个长度在 100 000 以内的正整数序列,大小不超过 10^12.  求一个连续子序列,使得在所有的连续子序列中,它们 ...

  3. 【模拟】2017 Multi-University Training Contest 1 The Battle of Chibi

    acm.hdu.edu.cn/showproblem.php?pid=5542 [Accepted] #include<iostream> #include<cstdio> # ...

  4. bzoj 2818 GCD 数论 欧拉函数

    bzoj[2818]Gcd Description 给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的数对(x,y)有多少对. Input 一个整数N Output 如题 Samp ...

  5. Mysql的常见几种错误:1045,1044

    Mysql的常见几种错误: 一.在进入 mysql 数据库时出错   # mysql -u root -p Enter password: ERROR 1045 (28000): Access den ...

  6. POJ 2749 2SAT判定+二分

    题意:图上n个点,使每个点都与俩个中转点的其中一个相连(二选一,典型2-sat),并使任意两点最大 距离最小(最大最小,2分答案),有些点相互hata,不能选同一个中转点,有些点相互LOVE,必需选相 ...

  7. POJ 2965 The Pilots Brothers' refrigerator【BFS+状压 Or 脑洞】

    题目链接: http://poj.org/problem?id=1753 题意: 给定冰箱门的开关情况,改变一个门则其所在行列的门都会发生改变,求出改变门的最少操作使得最终所有门都是打开状态. 代码: ...

  8. Python 列表的复制操作

    2013-10-18 10:07:03|   import copy a = [1,2,3,['a','b']] b = a c = a[:] d = copy.copy(a) e = copy.de ...

  9. 钱币兑换问题---hdu1284(完全背包)

    Problem Description 在一个国家仅有1分,2分,3分硬币,将钱N兑换成硬币有很多种兑法.请你编程序计算出共有多少种兑法.   Input 每行只有一个正整数N,N小于32768.   ...

  10. 转:String数组初始化

    近日,笔者在java编程中因为疏忽对String数组的初始化定义错误,导致程序运行出错.现将所理解的String数组在此进行说明,并对String数组初始化进行分析. //一维数组String[] s ...