【学习笔记】[AGC031F] Walk on Graph

这是一道数学题。

我尝试分析其周期性。结论是,一定存在 T T T使得 2 T = 1 2^T=1 2T=1,然而我并不知道 T T T的大小,暂时放一边。

然后我用 ( u , x ) (u,x) (u,x)描述当前在点 u u u,权值为 x x x,走一条长度为 d d d的边就变成了 ( v , 2 x + d ) (v,2x+d) (v,2x+d)。那么我走 T T T次相同的边,在 倒着做 的视角下不难看出权值仍为 x x x,如果 T T T是奇数那么其实是走到了 v v v,显然一定有解。如果 T T T是偶数,似乎规律不容易看出来。

然后我借鉴题解 注意到 ( u , x ) , ( v , 2 x + d ) (u,x),(v,2x+d) (u,x),(v,2x+d)双向可达 的,因此 ( u , x ) ⇔ ( v , 2 x + d ) (u,x)\Leftrightarrow(v,2x+d) (u,x)(v,2x+d),那么 ( u , 4 x + 3 d ) ⇔ ( u , x ) ⇔ ( u , 4 x + 3 d ′ ) (u,4x+3d)\Leftrightarrow(u,x)\Leftrightarrow(u,4x+3d') (u,4x+3d)(u,x)(u,4x+3d),因为 4 x 4x 4x可以表示任意数所以可以看成 ( u , x ) ⇔ ( u , x + 3 k ( d − d ′ ) ) (u,x)\Leftrightarrow(u,x+3k(d-d')) (u,x)(u,x+3k(dd)),其中 d , d ′ d,d' d,d是任取的与 u u u相连的两条边。那么记 t u t_u tu表示 u u u的周期,如果 u , v u,v u,v之间有边,那么 2 t u 2t_u 2tu也是 v v v的周期,所以 t v = gcd ⁡ ( 2 t u , t v ) = gcd ⁡ ( t u , t v ) t_v=\gcd(2t_u,t_v)=\gcd(t_u,t_v) tv=gcd(2tu,tv)=gcd(tu,tv),又因为图是联通的,所以记 g = gcd ⁡ i = 2 m ( d i − d 1 ) g=\gcd_{i=2}^m(d_i-d_1) g=gcdi=2m(did1),对于任意 u u u,有 ( u , x ) ⇔ ( u , x + 3 g ) (u,x)\Leftrightarrow(u,x+3g) (u,x)(u,x+3g)。这样我们把 ( u , x ) (u,x) (u,x)剖分成了 gcd ⁡ ( 3 g , mod ) \gcd(3g,\text{mod}) gcd(3g,mod)种情况。

方便起见,我们将模数等效成 gcd ⁡ ( 3 g , mod ) \gcd(3g,\text{mod}) gcd(3g,mod)。如果这个数比较小的话我们已经可以得到比较好的算法了。能否继续压缩呢?注意到 g ∣ d i − d 1 g|d_i-d_1 gdid1,所以 d i = k i g + d 1 d_i=k_ig+d_1 di=kig+d1,考虑将 d 1 d_1 d1扔掉,有一步反常的转化:可以将状态的 x x x都加上 d 1 d_1 d1,注意到这只是平移变换,只要满足原来的关系即可: ( u , x + d 1 ) ′ = ( u , x ) ⇔ ( v , 2 x + d 1 + k g ) = ( v , 2 x + 2 d 1 + k g ) ′ (u,x+d_1)'=(u,x)\Leftrightarrow(v,2x+d_1+kg)=(v,2x+2d_1+kg)' (u,x+d1)=(u,x)(v,2x+d1+kg)=(v,2x+2d1+kg),也就是说平移不改变连通性。显然 k g kg kg也可以被扔掉,因为 ( u , x ) ⇔ ( v , 2 x + k g ) ⇔ ( u , 4 x ) (u,x)\Leftrightarrow(v,2x+kg)\Leftrightarrow(u,4x) (u,x)(v,2x+kg)(u,4x)。那么考虑以 ( u , x ) (u,x) (u,x)为起点能到的点都可以表示成 ( v , 2 i x + j g ) (v,2^ix+jg) (v,2ix+jg),其中 i ∈ { 0 , 1 } , j ∈ { 0 , 1 , 2 } i\in \{0,1\},j\in \{0,1,2\} i{0,1},j{0,1,2},也就是说一个点有用的状态只有 6 6 6种。

那么,起点可以看成 ( u , 0 , 0 ) (u,0,0) (u,0,0),对于终点,我们可以解出所有的 ( v , i , j ) (v,i,j) (v,i,j),然后判断是否在同一个连通块中即可。我们发现,这样的表示并不取决于终点的选取,因此只需建一次图即可。

复杂度 O ( mod + 6 n ) O(\text{mod}+6n) O(mod+6n)

#include<bits/stdc++.h> #define fi first #define se second #define ll long long #define pb push_back #define inf 0x3f3f3f3f using namespace std; const int N=50005; const int M=1e6+5; int n,m,Q,mod,g,U[N],V[N],W[N],fa[N*6],id[N][2][3],num,v[2][M]; int gcd(int x,int y){ return y==0?x:gcd(y,x%y); } int find(int x){ return fa[x]==x?x:fa[x]=find(fa[x]); } void unionset(int x,int y){ if(find(x)!=find(y))fa[fa[x]]=fa[y]; } int solve(int x,int y,int z){ for(int i=0;i<2;i++){ for(int j=0;j<3;j++){ if(v[i][(W[1]+z+(3-j)*g)%mod]&&find(id[x][0][0])==find(id[y][i][j])){ return 1; } } }return 0; } signed main(){ cin>>n>>m>>Q>>mod; for(int i=1;i<=m;i++)cin>>U[i]>>V[i]>>W[i]; for(int i=2;i<=m;i++)g=gcd(g,abs(W[i]-W[1])); mod=gcd(mod,3*g);for(int i=1;i<=n;i++)for(int j=0;j<2;j++)for(int k=0;k<3;k++)id[i][j][k]=++num; for(int i=1;i<=num;i++)fa[i]=i; for(int i=1;i<=m;i++){ int w; if(g>0)w=(W[i]-W[1])/g%3; else w=0; for(int j=0;j<2;j++){ for(int k=0;k<3;k++){ unionset(id[U[i]][j][k],id[V[i]][j^1][(k*2+3+w)%3]); unionset(id[V[i]][j][k],id[U[i]][j^1][(k*2+3+w)%3]); } } }for(int i=0;i<2;i++){ int k=W[1]%mod;if(i)k=k*2%mod; for(int j=0;j<mod;j++){ v[i][k]=1;k=k*4%mod; } } for(int i=1;i<=Q;i++){ int x,y,z;cin>>x>>y>>z; cout<<(solve(y,x,z)?"YES":"NO")<<"\n"; } }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530054.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(10)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示