【学习笔记】[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";
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值