【题解】AtCoder-ABC306_G Return to 1
这也太强了!
容易想到的是用若干环拼出这个 ,也就是这些环的 。
之后就不会了。
先正图反图两次 DFS,只留下 所在强连通分量里的边,对正图跑 DFS 生成树,定义其深度从 开始,然后有一个结论是:对于任何正整数 ,图中存在一个包含 的且长度不是 的倍数的环的充要条件是存在一条图上的边 使 。
下面是证明。
必要性考虑证明逆否命题,即若不存在一条图上的边 使 ,则图中包含 的环的长度都是 的倍数。这是显然的,由于这样的环深度从 开始,每次移动都相当于深度在模 意义下加 ,又回到 ,所以环长一定是 的倍数。
充分性不知道题解在说什么,但是若存在这样 的边,就说明 是非树边且 和 是由两条不同的根链遍历到的,由于 ,那么 的根链长加 与 的根链长,在模 意义下不同余,也就是两条 到 的路径长不同余。这时候同样是从 回到 ,两个环长度一定不同余,那么至少有一个不是 的倍数。
这样我们对所有环求 就可以对所有 求 。
点击查看代码
int t;
int n,m;
vector<int> E1[maxn],E2[maxn];
bool vis1[maxn],vis2[maxn];
int dep[maxn];
void dfs1(int u,int d){
vis1[u]=true,dep[u]=d;
for(int v:E1[u]){
if(vis1[v]) continue;
dfs1(v,d+1);
}
}
void dfs2(int u){
vis2[u]=true;
for(int v:E2[u]){
if(vis2[v]) continue;
dfs2(v);
}
}
int main(){
t=read();
while(t--){
n=read(),m=read();
for(int i=1;i<=n;++i){
E1[i].clear(),E2[i].clear();
vis1[i]=false,vis2[i]=false,dep[i]=0;
}
for(int i=1;i<=m;++i){
int u=read(),v=read();
E1[u].push_back(v);
E2[v].push_back(u);
}
dfs1(1,0);
dfs2(1);
int g=0;
for(int u=1;u<=n;++u){
if(!vis1[u]||!vis2[u]) continue;
for(int v:E1[u]){
if(!vis1[v]||!vis2[v]) continue;
if(!g) g=abs(dep[u]+1-dep[v]);
else g=__gcd(g,abs(dep[u]+1-dep[v]));
}
}
if(!g) printf("No\n");
else{
while(g%2==0) g/=2;
while(g%5==0) g/=5;
if(g==1) printf("Yes\n");
else printf("No\n");
}
}
return 0;
}
作者:SoyTony
出处:https://www.cnblogs.com/SoyTony/p/Solution_on_AtCoder-ABC306_G.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
合集:
题解
分类:
A/题解
, 数学/数论/欧几里得算法及扩展
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效