题目描述

有一天,牛牛找到了一个巨大的洞穴。洞穴可以描述成一个有向图,一共有\(N\)个节点(从\(1\)到\(N\)编号)和\(M\)条长度为\(1\)的有向边,每条边从某一个节点\(u\)连向另一个节点\(v\)(\(u\)可能等于\(v\))。
为了更好的探索洞穴,牛牛向你提出了\(Q\)个问题,每个问题给定两个节点\(a,b\)以及一个数\(l\), 你需要告诉牛牛是否存在一条开始于\(a\), 结束于\(b\)的路径,总长度为\(l\)。(路径中可以经过任意点、边多次,但只能沿着单向边给定的方向行走,不允许反向行走)。

输入描述:

第一行两个数\(N, M\)代表点数和边数
接下来M行每行两个整数\(u_i, v_i\)代表第\(i\)条边从\(u_i\)连向\(v_i\),长度为\(1\)
接下来一个整数\(Q\)代表牛牛的问题数
接下来\(Q\)行每行三个整数\(l_i, a_i, b_i\)代表牛牛的一个询问

\(20\%\)的数据, \(1 \leq M \leq 30\), \(1 \leq li \leq 5\)
\(50\%\)的数据, \(1 \leq li \leq 100\)
\(100\%\)的数据, \(1 \leq N \leq 100\), \(1 \leq M \leq 10000\), \(1 \leq Q \leq 1000\), \(1 \leq l_i \leq 10^9\) ,\(1 \leq a_i, b_i, u_i, v_i \leq N\)

输出描述:

输出\(Q\)行依次回答牛牛的\(Q\)个询问
每行输出YESNOYES代表存在符合条件的路径,NO代表不存在

示例1

输入

3 3
1 2
2 3
3 1
3
100 1 1
100 1 2
100 1 3

输出

NO
YES
NO

说明

这个图是一个三元环,从\(1\)号点开始走\(100\)步之后必定停在\(2\)号点上

Solution

嗯,先说50分的暴力分,显然就是一个裸的记忆化搜索结束。

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
#define lowbit(x) ((x)&(-(x)))
#define REP(i,a,n) for(register int i=(a);i<=(n);++i)
#define PER(i,a,n) for(register int i=(a);i>=(n);--i)
#define FEC(i,x) for(register int i=head[x];i;i=g[i].ne)
#define dbg(...) fprintf(stderr,__VA_ARGS__)
namespace io{const int SIZE=(1<<21)+1;char ibuf[SIZE],*iS,*iT,obuf[SIZE],*oS=obuf,*oT=oS+SIZE-1,c,qu[55];int f,qr;#define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),(iS==iT?EOF:*iS++)):*iS++)inline void flush(){fwrite(obuf,1,oS-obuf,stdout);oS=obuf;}inline void putc(char x){*oS++=x;if(oS==oT)flush();}template<class I>inline void read(I &x){for(f=1,c=gc();c<'0'||c>'9';c=gc())if(c=='-')f=-1;for(x=0;c<='9'&&c>='0';c=gc())x=x*10+(c&15);x*=f;}template<class I>inline void write(I x){if(!x)putc('0');if(x<0)putc('-'),x=-x;while(x)qu[++qr]=x%10+'0',x/=10;while(qr)putc(qu[qr--]);}inline void print(const char *s){while(*s!='\0')putc(*s++);}inline void scan(char *s){for(c=gc();c<=' ';c=gc());for(;c>' ';c=gc())*(s++)=c;*s='\0';}struct Flusher_{~Flusher_(){flush();}}io_flusher_;
}//orz laofudasuan
using io::read;using io::putc;using io::write;using io::print;
typedef long long ll;typedef unsigned long long ull;
template<typename A,typename B>inline bool SMAX(A&x,const B&y){return x<y?x=y,1:0;}
template<typename A,typename B>inline bool SMIN(A&x,const B&y){return y<x?x=y,1:0;}const int N=100+7,M=100000+7;
int n,m,Q,x,y,z;char vis[N][N][N],dp[N][N][N];
struct Edge{int to,ne;}g[M];int head[N],tot;
inline void Addedge(int x,int y){g[++tot].to=y;g[tot].ne=head[x];head[x]=tot;}inline char DFS(int x,int y,int z){if(vis[x][y][z])return dp[x][y][z];if(x==y&&z==0)return dp[x][y][z]=vis[x][y][z]=1;if(x!=y&&z==0)return vis[x][y][z]=1,dp[x][y][z]=0;char &ans=dp[x][y][z];vis[x][y][z]=1;for(register int i=head[x];i;i=g[i].ne)if(ans=(ans||DFS(g[i].to,y,z-1)))return ans=1;return ans;
}int main(){
#ifndef ONLINE_JUDGEfreopen("C.in","r",stdin);freopen("C.out","w",stdout);
#endifread(n),read(m);for(register int i=1;i<=m;++i)read(x),read(y),Addedge(x,y);read(Q);for(register int i=1;i<=Q;++i){read(z),read(x),read(y);io::print(DFS(x,y,z)?"YES\n":"NO\n");}
}

然后考场上,我想了一会儿,感觉\(10^9\)的范围简直就是倍增的暗示,于是立刻1分钟敲了一个\(O(n^3\log n)\)的东西预处理出\(f[i][j][k]\)表示从\(i\)到\(j\)花了\(2^k\)步是否可行。

然后就想了两个小时怎么处理询问,然候这个叫hkk的傻逼愣是没想到bitset这种东西。

我们定义一个bitset类型的数组\(f[i][j]\)存下从\(i\)出发,走了\(2^j\)步可以到达的点。

于是\(O(\frac{n^3\log n}{32})\)预处理出\(f\)数组。

然后查询的时候倍增跳长度,每一次跳的时候再用bitset压一下从\(x\)跳目前倍增到的长度可以到达那些店,随便搞搞就行了。

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<bitset>
using namespace std;
#define lowbit(x) ((x)&(-(x)))
#define REP(i,a,n) for(register int i=(a);i<=(n);++i)
#define PER(i,a,n) for(register int i=(a);i>=(n);--i)
#define FEC(i,x) for(register int i=head[x];i;i=g[i].ne)
#define dbg(...) fprintf(stderr,__VA_ARGS__)
namespace io{const int SIZE=(1<<21)+1;char ibuf[SIZE],*iS,*iT,obuf[SIZE],*oS=obuf,*oT=oS+SIZE-1,c,qu[55];int f,qr;#define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),(iS==iT?EOF:*iS++)):*iS++)inline void flush(){fwrite(obuf,1,oS-obuf,stdout);oS=obuf;}inline void putc(char x){*oS++=x;if(oS==oT)flush();}template<class I>inline void read(I &x){for(f=1,c=gc();c<'0'||c>'9';c=gc())if(c=='-')f=-1;for(x=0;c<='9'&&c>='0';c=gc())x=x*10+(c&15);x*=f;}template<class I>inline void write(I x){if(!x)putc('0');if(x<0)putc('-'),x=-x;while(x)qu[++qr]=x%10+'0',x/=10;while(qr)putc(qu[qr--]);}inline void print(const char *s){while(*s!='\0')putc(*s++);}inline void scan(char *s){for(c=gc();c<=' ';c=gc());for(;c>' ';c=gc())*(s++)=c;*s='\0';}struct Flusher_{~Flusher_(){flush();}}io_flusher_;
}//orz laofudasuan
using io::read;using io::putc;using io::write;using io::print;
typedef long long ll;typedef unsigned long long ull;
template<typename A,typename B>inline bool SMAX(A&x,const B&y){return x<y?x=y,1:0;}
template<typename A,typename B>inline bool SMIN(A&x,const B&y){return y<x?x=y,1:0;}const int N=100+7,M=100000+7,LOG=31;
int n,m,Q,x,y,z;bitset<N>f[N][LOG],pre,now;
struct Edge{int to,ne;}g[M];int head[N],tot;
inline void Addedge(int x,int y){g[++tot].to=y;g[tot].ne=head[x];head[x]=tot;}inline void Preprocess(){for(register int k=1;k<LOG;++k)for(register int i=1;i<=n;++i)for(register int j=1;j<=n;++j)if(f[i][k-1].test(j))f[i][k]|=f[j][k-1];
}int main(){
#ifndef ONLINE_JUDGEfreopen("C.in","r",stdin);freopen("C.out","w",stdout);
#endifread(n),read(m);for(register int i=1;i<=m;++i)read(x),read(y),f[x][0].set(y);Preprocess();read(Q);for(register int i=1;i<=Q;++i){read(z);read(x),read(y);now.reset();now.set(x);for(register int k=LOG-1;k>=0;--k)if((1<<k)&z){pre=now,now.reset();for(register int j=1;j<=n;++j)if(pre.test(j))now|=f[j][k];}print(now.test(y)?"YES\n":"NO\n");}
}

转载于:https://www.cnblogs.com/hankeke/p/nowcoder-noiptg7-C.html

牛客网NOIP赛前集训营-提高组(第七场)C-洞穴相关推荐

  1. 牛客网NOIP赛前集训营 提高组 第5场 T2 旅游

    [题解] 我们可以发现不在最小生成树上的边一定不能多次经过,因为一条不在最小生成树上的边(u,v)的边权比最小生成树上(u,v)之间的路径更长,选择不在最小生成树上的边一定不划算. 我们还需要确定最小 ...

  2. 牛客网NOIP赛前集训营 提高组(第七场)

    中国式家长 2 链接:https://www.nowcoder.com/acm/contest/179/A 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K ...

  3. 牛客网NOIP赛前集训营-提高组(第六场)B-选择题

    题目描述 有一道选择题,有 a,b,c,d 四个选项. 现在有 n 个人来做这题,第 i 个人有 pi,j 的概率选第 j 个选项. 定义\(cnt(x)\)为选第$ x $个选项的人数. 令\(mx ...

  4. 牛客网NOIP赛前集训营-提高组(第六场)B-选择题[背包]

    题意 题目链接 分析 直接背包之后可以 \(O(n)\) 去除一个物品的影响. 注意特判 \([p==1]\) 的情况. 总时间复杂度为 \(O(n^2)\) . 代码 #include<bit ...

  5. [NowCoder]牛客网NOIP赛前集训营-提高组(第六场)题解

    A.最长路 题意:给定有向图,每条边有个字符\([0,10^9]\),求每个点最长路字典序最小的方案.\(N,M\le 10^6\) 建反图跑拓扑排序,显然入过队的点都有最长路,考虑如何判断字典序大小 ...

  6. 牛客网NOIP赛前集训营-提高组(第七场)C 洞穴

    洞穴 思路: 矩阵乘法 由于只需要知道 A ^ l 的 第a行第b个元素 所以我们每次在做矩阵乘法时只需要算第a行就可以了 还要像矩阵快速幂一样预处理A ^ (1<<d) 代码: #pra ...

  7. 【题解】[牛客网NOIP赛前集训营-提高组(第七场)]C.洞穴 倍增优化DP+bitset

    题目链接 #include<cstdio> #include<bitset> using namespace std; const int N=110; int n,m,q; ...

  8. 牛客网NOIP赛前集训营-普及组(第一场)

    前三题略 T4: 题目描述 小A有n个长度都是L的字符串.这些字符串只包含前8个小写字符,'a'~'h'.但这些字符串非常的混乱,它们几乎长得互不相同.小A想通过一些规则,让它们长得尽可能相同.小A现 ...

  9. Nowcoder | [题解-N165]牛客网NOIP赛前集训营-普及组(第二场)

    啊...表示一大早还没睡醒就开始打比赛(开始前一分钟的我还在桌子上趴着休眠)...表示题目思路清奇(尤其C题)...但是我还是太蒻了...\(D\)题暴力都没打...题解正式开始之前先\(\%\)一下 ...

最新文章

  1. 开发高性能JAVA应用程序基础(内存篇)
  2. vue踩坑记-在项目中安装依赖模块npm install报错
  3. mysql 快速升级_MySQL 4到5的快速升级
  4. c语言opengles程序,OpenGL ES _ 着色器_程序
  5. PyQT5-QProgressBar
  6. 一天天过得很快啊,今天大家都干了啥?我们拿出来晒晒
  7. github项目提交失败 master - master (non-fast-forward)
  8. 我靠! 算你运气好 a joke
  9. 李永乐线性代数辅导讲义第四章学霸小结
  10. ruby所有版本下载地址
  11. GPIO模拟MDC/MDIO协议
  12. eclipse 实用的快捷键
  13. MMC 事件查看器无法打开
  14. Docker容器内部 DNS 解析失败的问题
  15. Aruba 无线调试(Instant AP)
  16. 20171028_艾孜_Java_第二次
  17. 新网站关键词优化小技巧
  18. pdf合并与拆分软件的使用
  19. 关于ISO26262功能安全管理的理解
  20. 提交和复位按钮的知识(Submit Reset Buttons)

热门文章

  1. 层次聚类(Hierarchical Clustering)——CURE算法详解及举例
  2. Linux Shell脚本 Linux C程序 获取指定的范围内 or 系统可用端口
  3. IOS8键盘模拟器无法显示,真机可以
  4. ROS noetic 安装编译Cartographer踩坑记录
  5. 计算机stem项目计划书,钟声学校STEM教育计划书1617-1718.PDF
  6. 8- OpenCV+TensorFlow 入门人工智能图像处理-浮雕效果油画效果
  7. iOS自带定位获取地址
  8. ZH-HPLC-485型HPLC转RS485透传模块在分布式光伏并网逆变器发电数据采集器装置中的应用方案
  9. 3d弹弹球(加强版)
  10. Python3练习-打印一个倒立三角形