nowcoder 提高组模拟赛 最长路 解题报告
最长路
链接:
https://www.nowcoder.com/acm/contest/178/A
来源:牛客网
题目描述
有一张 \(n\) 个点 \(m\) 条边的有向图,每条边上都带有一个字符,字符用一个数字表示。
求以每个点为起点的最长路,输出走过的边的字符构成的字符串的字典序最小的方案。
为了方便,你需要这样输出方案:
如果最长路无限长,则输出Infinity
否则假设方案走过的边的字符依次为 \(w_1,w_2,\cdots,w_k\) ,输出\((\sum\limits_{i=1}^kw_i\times29^i) \bmod 998244353\)
输入描述:
第一行两个整数 \(n\),\(m\) ,表示有向图的结点个数和边数。
接下来 \(m\) 行,每行三个整数 \(x,y,w\) ,表示有一条从 \(x\) 连向 \(y\) 的边,上面有字符 \(w\) 。
输出描述:
共 \(n\) 行,第 \(i\) 行表示第 \(i\) 个点所求的方案,输出方式见题目描述。
备注:
全部的输入数据满足:
- \(1 ≤ n ≤ 1000000\)
- \(1 ≤ m ≤ 1000000\)
- \(0 ≤ \text{字符} ≤ 10^9\)
各个测试点的性质如下:(若为空,则表示没有特殊性质)
测试点标号 | n | m | 特殊性质 |
---|---|---|---|
\(1,2,3,4\) | \(\le 1000\) | \(\le 1000\) | |
\(5,6\) | 所有字符=0 | ||
\(7,8\) | 所有字符相等 | ||
\(9,10,11,12,13,14,15,16\) | 所有字符互不相等 | ||
\(17,18\) | \(\le 200000\) | \(\le 200000\) | |
\(19,20\) |
如果脑子傻了先缩个点就爆0了。。有向图有自环时直接tarjan出不来的哦~
直接反向\(topo\)排序进不去就可以判有没有经过环了。
如果没有字典序的要求显然就是一个最长路的简单题。
考虑如何使字典序最小,题解给出了两个做法,我就两个都写了写。
方法\(1\),在最短路树上维护倍增数组。
我们发现,简单的判断字典序是没法判断一个正在转移别人的点之前的路径的,如果连出去的边和连出去的点之前的转移值的那条边相等,我们就没得办法了。
为了可以判断,我们对路径的值维护一个\(hash\)值,来判断两条路径是否相等,通过倍增找到路径不相等的地方并进行比较。
复杂度\(O(nlogn)\)
Code:
#include <cstdio>
#define ll long long
const int N=1e6+10;
const ll mod=998244353ll;
int head[N],to[N],edge[N],Next[N],cnt;
void add(int u,int v,int w)
{
to[++cnt]=v,edge[cnt]=w,Next[cnt]=head[u],head[u]=cnt;
}
ll po[N];
int n,m,in[N],f[N][21],pre[N],q[N],l=1,r=0;
ll g[N][21];
struct node
{
int u,las,len;ll ans;
bool friend operator <(node n1,node n2)
{
if(n1.len!=n2.len||n1.las!=n2.las) return n1.len==n2.len?n1.las>n2.las:n1.len<n2.len;
int u1=n1.u,u2=n2.u;
for(int i=20;~i;i--)
if(f[u1][i]&&g[u1][i]==g[u2][i])
u1=f[u1][i],u2=f[u2][i];
return pre[u1]>pre[u2];
}
}dp[N],t;
node max(node n1,node n2){return n1<n2?n2:n1;}
int main()
{
scanf("%d%d",&n,&m);
po[0]=1;
for(int i=1;i<=n;i++) po[i]=po[i-1]*29ll%mod;
for(int u,v,w,i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
add(v,u,w),in[u]++;
}
for(int i=1;i<=n;i++)
if(!in[i]) q[++r]=i;
while(l<=r)
{
int now=q[l++];
for(int i=head[now];i;i=Next[i])
{
int v=to[i];
in[v]--;
t={now,edge[i],dp[now].len+1,(dp[now].ans+edge[i])*29ll%mod};
dp[v]=max(dp[v],t);
if(!in[v])
{
f[v][0]=dp[v].u;
g[v][0]=dp[v].las;
pre[v]=dp[v].las;
for(int k=1;f[v][k-1];k++)
{
f[v][k]=f[f[v][k-1]][k-1];
g[v][k]=(g[f[v][k-1]][k-1]*po[1<<k-1]+g[v][k-1])%mod;
}
q[++r]=v;
}
}
}
for(int i=1;i<=n;i++)
{
if(in[i]) puts("Infinity");
else printf("%lld\n",dp[i].ans);
}
return 0;
}
方法\(2\),根据最长路的长度把点分层。
这个方法更加巧妙,常数也更小。
先把最长路求出来,然后对每个点安排它的层数,排除了一些无用边。
那么同层的点就可以按照路径字典序来判断这个点之前的路径了。
具体的,对这层向下层的点连的边排序,以边的权值为第一关键字,以上层的点的字典序为第二关键字就行了。
Code:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define ll long long
const ll mod=998244353ll;
const int N=1e6+10;
int dis[N],edge[N],head[N],to[N],Next[N],cnt;
void add(int u,int v,int w)
{
to[++cnt]=v,edge[cnt]=w,Next[cnt]=head[u],head[u]=cnt;
}
int q[N],l=1,r=0,n,m,mx,in[N],pre[N];
ll ans[N];
using std::vector;
int max(int x,int y){return x>y?x:y;}
vector <int> pot[N];
struct node
{
int u,v,w,pre;
bool friend operator <(node n1,node n2)
{
return n1.w==n2.w?n1.pre<n2.pre:n1.w<n2.w;
}
}e[N];
int main()
{
scanf("%d%d",&n,&m);
for(int u,v,w,i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
add(v,u,w),++in[u];
}
memset(dis,-1,sizeof(dis));
for(int i=1;i<=n;i++)
if(!in[i])
q[++r]=i,dis[i]=0;
while(l<=r)
{
int now=q[l++];
for(int i=head[now];i;i=Next[i])
{
int v=to[i];
--in[v];
dis[v]=max(dis[v],dis[now]+1);
mx=max(dis[v],mx);
if(!in[v]) q[++r]=v;
}
}
for(int i=1;i<=n;i++)
if(~dis[i]) pot[dis[i]].push_back(i);
int d=0;
do
{
int tot=0,tot0=0;
for(int i=0;i<pot[d].size();i++)
for(int j=head[pot[d][i]];j;j=Next[j])
if(dis[to[j]]==d+1)
e[++tot]={pot[d][i],to[j],edge[j],pre[pot[d][i]]};
std::sort(e+1,e+1+tot);
for(int i=1;i<=tot;i++)
if(!pre[e[i].v])
{
pre[e[i].v]=++tot0;
ans[e[i].v]=(ans[e[i].u]+e[i].w)*29ll%mod;
}
d++;
}while(d<mx);
for(int i=1;i<=n;i++)
{
if(in[i]) puts("Infinity");
else printf("%lld\n",ans[i]);
}
return 0;
}
2018.10.21
nowcoder 提高组模拟赛 最长路 解题报告的更多相关文章
- nowcoder(牛客网)提高组模拟赛第四场 解题报告
T1 动态点分治 就是模拟..... 但是没有过!! 看了题解之后发现.... 坑点:有可能 \(x<=r\),但是
- nowcoder 提高组模拟赛 选择题 解题报告
选择题 链接: https://www.nowcoder.com/acm/contest/178/B 来源:牛客网 题目描述 有一道选择题,有 \(a,b,c,d\) 四个选项. 现在有 \(n\) ...
- NOIP2017提高组模拟赛 9 (总结)
NOIP2017提高组模拟赛 9 (总结) 第一题 星星 天空中有N(1≤N≤400)颗星,每颗星有一个唯一的坐标(x,y),(1≤x,y ≤N).请计算可以覆盖至少K(1≤K≤N)颗星的矩形的最小面 ...
- NOIP2017提高组模拟赛4 (总结)
NOIP2017提高组模拟赛4 (总结) 第一题 约数 设K是一个正整数,设X是K的约数,且X不等于1也不等于K. 加了X后,K的值就变大了,你可以重复上面的步骤.例如K= 4,我们可以用上面的规则产 ...
- ZROI提高组模拟赛05总结
ZROI提高组模拟赛05总结 感觉是目前为止最简单的模拟赛了吧 但是依旧不尽人意... T1 有一半的人在30min前就A掉了 而我花了1h11min 就是一个简单的背包,我硬是转化了模型想了好久,生 ...
- NOIP2017提高组 模拟赛15(总结)
NOIP2017提高组 模拟赛15(总结) 第一题 讨厌整除的小明 [题目描述] 小明作为一个数学迷,总会出于数字的一些性质喜欢上某个数字,然而当他喜欢数字k的时候,却十分讨厌那些能够整除k而比k小的 ...
- NOIP2017提高组 模拟赛13(总结)
NOIP2017提高组 模拟赛13(总结) 第一题 函数 [题目描述] [输入格式] 三个整数. 1≤t<10^9+7,2≤l≤r≤5*10^6 [输出格式] 一个整数. [输出样例] 2 2 ...
- NOIP2017提高组模拟赛 10 (总结)
NOIP2017提高组模拟赛 10 (总结) 第一题 机密信息 FJ有个很奇怪的习惯,他把他所有的机密信息都存放在一个叫机密盘的磁盘分区里,然而这个机密盘中却没有一个文件,那他是怎么存放信息呢?聪明的 ...
- NOIP2017提高组模拟赛 8(总结)
NOIP2017提高组模拟赛 8(总结) 第一题 路径 在二维坐标平面里有N个整数点,Bessie要访问这N个点.刚开始Bessie在点(0,0)处. 每一步,Bessie可以走到上.下.左.右四个点 ...
随机推荐
- 使用virtual安装Windows系列操作系统总结
最近在安装Windows操作系统的过程中,发现总是报错,无法安装成功,后来经过不断地摸索,发现根本的问题在于镜像,所以在以后的大文件传输下载后,一定要校验其MD5值是否与源文件一致,需要的朋友可以联系 ...
- chromedriver各个版本的下载
驱动的下载地址如下: http://chromedriver.storage.googleapis.com/index.html 注意:64位向下兼容,直接下载32位的就可以啦,亲测可用.
- stm32+lwip(三):TCP测试
我是卓波,很高兴你来看我的博客. 系列文章: stm32+lwip(一):使用STM32CubeMX生成项目 stm32+lwip(二):UDP测试 stm32+lwip(三):TCP测试 stm32 ...
- 笔记-flask-原理及请求处理流程
笔记-flask-原理及请求处理流程 1. 服务器声明及运行 最基本的flask项目代码如下 from flask import Flask app = Flask(__name__) @a ...
- 关于 js 对象 转 字符串 和 深拷贝 的探讨
随着更多语言的支持 **json** 作为数据传输和存储的媒体,已经非常成熟且应用广泛.却存在致命硬伤,不携带 **对象方法** .在数据传输和存储中,这是恰当的和合理的. 但是在更多的应用场景中,又 ...
- Java Web前后端分离的思考与实践
第一节 Java Web开发方式的变化 Web开发虽然是我们常说的B/S模式,其实本质上也是一种特殊的C/S模式,只不过C和S的选择余地相对要窄了不少,而且更标准化.不论是采用什么浏览器和后端框架,W ...
- 位运算 & 网络序字节序
一.初识位运算 位运算,见词明意,二进制运算,通常需要将运算数转换为二进制再进行处理,如果是在程序语言中则无需自己进行进制转换,基本的位操作符有如下几种:与(&).或(|).异或(^).取反( ...
- jmeter动态获取jsessionid
思想是在一个线程组内添加一个cookie管理器,登录之后,用正则提取到sessionid,该线程组下的操作便可以共享这个session了. 1. 依次新建线程组.cookie管理器.http请求-登录 ...
- Linux-Qt Quick学习1-Hello world
Qt作为共平台的开发IDE.实在是强大,在Quick的学习中,与平台无关,我这里使用ubuntu和openSUSE,之所以不用Windows,是因为我想借这个机会过学习一点linux的东西,哪怕是熟悉 ...
- 【性能调优】一次关于慢查询及FGC频繁的调优经历
以下来分享一个关于MySQL数据库慢查询和FGC频繁的性能案例. 一.系统架构 一个简单的dubbo服务,服务提供者提供接口,并且提供接口的实现,提供方注册服务到Zookeeper注册中心,然后消费者 ...