这是一道数学题。
我尝试分析其周期性。结论是,一定存在 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(d−d′)),其中
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(di−d1),对于任意
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 g∣di−d1,所以 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 } iin {0,1},jin {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";
}
}
最后
以上就是机灵发卡最近收集整理的关于【学习笔记】[AGC031F] Walk on Graph的全部内容,更多相关【学习笔记】[AGC031F]内容请搜索靠谱客的其他文章。
发表评论 取消回复