我是靠谱客的博主 美好书本,最近开发中收集的这篇文章主要介绍Atcoder agc031F,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

真神题,对着题解想了一天才想明白。具体题解租酥雨的博客写得很好了。这里可能就是复述了一遍他的题解。
考虑倒着做,每次就是把当前和 ∗ 2 *2 2再加上当前边的权值。把在点 x x x且和为 c c c的状态称作 ( x , c ) (x,c) (x,c),即问从 ( T , 0 ) (T,0) (T,0)能否到达 ( S , R ) (S,R) (S,R)。先注意到状态之间的转移是可逆的(来回走一条边即可),那么只用判断连通性。
再注意到如果点 x x x有两条边权为 u u u v v v的出边,不妨设分别到点 u ′ u' u v ′ v' v,我们就可以由 ( x , c ) ≃ ( u ′ , 2 c + u ) ≃ ( x , 4 c + 3 u ) (x,c)simeq(u',2c+u)simeq(x,4c+3u) (x,c)(u,2c+u)(x,4c+3u) ( x , c ) ≃ ( v ′ , 2 c + v ) ≃ ( x , 4 c + 3 v ) (x,c)simeq(v',2c+v)simeq(x,4c+3v) (x,c)(v,2c+v)(x,4c+3v)推出 ( x , c ) ≃ ( x , c + 3 ( u − v ) ) (x,c)simeq(x,c+3(u-v)) (x,c)(x,c+3(uv))。进一步的可以推出某个点两个和差图中任意两条边边权差的 3 3 3倍的状态都是等价的。不妨设图中任意两条边边权差的 gcd ⁡ gcd gcd g g g,那么可以将 M O D MOD MOD变为 gcd ⁡ ( M O D , 3 g ) gcd(MOD,3g) gcd(MOD,3g)
现在可能的状态数还是很大,不过我们发现任意两条边边权   m o d     g bmod g mod g都是相等的,将它设为 z z z,那么每条边的权值在   m o d     M O D bmod MOD mod MOD意义下为 p g + z ( p ∈ { 0 , 1 , 2 } ) pg+z(p in {0,1,2}) pg+z(p{0,1,2})。如果我们将和在   m o d     M O D bmod MOD mod MOD意义下加 z z z,每条边边权在   m o d     M O D bmod MOD mod MOD意义下减 z z z,可以发现操作是不变的( ( x , c ) ≃ ( u , 2 c + ( p g + z ) ) (x,c)simeq(u,2c+(pg+z)) (x,c)(u,2c+(pg+z))变为 ( x , c + z ) ≃ ( u , 2 ( c + z ) + ( ( p g + z ) − z ) (x,c+z)simeq(u,2(c+z)+((pg+z)-z) (x,c+z)(u,2(c+z)+((pg+z)z))。这样的话经过 d d d步后, ( x , c ) (x,c) (x,c)只会变成 ( u , 2 d c + p g ) ( p ∈ { 0 , 1 , 2 } ) (u,2^dc+pg)(p in { 0,1,2}) (u,2dc+pg)(p{0,1,2}),并且我们来回走一条边的话, p p p不变, d d d会加 2 2 2,于是可以将 d d d变为 d   m o d   2 d bmod 2 dmod2
这样就只有 6 n 6n 6n个状态了,直接并查集预处理连通性即可。询问的时候即为查询是否有 ( T , z ) ≃ ( S , R + z ) (T,z)simeq(S,R+z) (T,z)(S,R+z),预处理每个数是否在   m o d     M O D bmod MOD mod MOD意义下是否是 2 2 2的奇/偶次幂,就可以暴力枚举几种情况判定了。
时间复杂度 O ( ( n + m + q ) α ( n ) ) mathcal O((n+m+q)alpha(n)) O((n+m+q)α(n))

#include <bits/stdc++.h>
#define last last2
#define FR first
#define SE second

using namespace std;

typedef pair<int,int> pr;

namespace SETS {

int fa[300005];

void init(int n) {
  for(int i=1;i<=n;i++) fa[i]=i;
}

int find_father(int x) {
  return (fa[x]==x)?x:fa[x]=find_father(fa[x]);
}

bool check(int x,int y) {
  x=find_father(x);y=find_father(y);
  return x==y;
}

void merge(int x,int y) {
  x=find_father(x);y=find_father(y);
  if (x==y) return;
  fa[x]=y;
}

}

inline int id(int x,int y,int z) {
  return (x-1)*6+y*2+z+1;
}

vector <pr> e[50005];

bool vis[2][1000005];

void pre(int s,int mod) {
  for(int i=0,j=s;i<(mod<<1);i++,j=j*2%mod)
    vis[i&1][j]=1;
}

int main() {
  int n,m,k,mod;
  scanf("%d%d%d%d",&n,&m,&k,&mod);
  int g=0,last=-1;
  for(int i=1;i<=m;i++) {
  	int x,y,z;
  	scanf("%d%d%d",&x,&y,&z);
  	e[x].push_back(pr(y,z));
  	e[y].push_back(pr(x,z));
  	if (last!=-1) g=__gcd(g,abs(z-last)); 
  	last=z;
  }
  if (!g) g=mod;
  mod=__gcd(mod,3*g);
  int v=e[1][0].SE%g;
  pre(v,mod);
  SETS::init(6*n);
  for(int i=1;i<=n;i++)
    for(int j=0;j<e[i].size();j++) {
    	int u=e[i][j].FR,v=e[i][j].SE/g;
    	for(int k=0;k<3;k++) {
    		SETS::merge(id(i,k,0),id(u,(2*k+v)%3,1));
    		SETS::merge(id(i,k,1),id(u,(2*k+v)%3,0));
		}
	}
  for(int i=1;i<=k;i++) {
  	int x,y,z;
  	scanf("%d%d%d",&x,&y,&z);
  	z=(z+v)%mod;
  	bool ok=0;
  	for(int j=0;j<3;j++)
  	  for(int k=0;k<2;k++)
  	    if (SETS::check(id(y,0,0),id(x,j,k))&&vis[k][(z-j*g%mod+mod)%mod]) ok=1;
  	puts((ok)?"YES":"NO");
  }
  return 0;
}

最后

以上就是美好书本为你收集整理的Atcoder agc031F的全部内容,希望文章能够帮你解决Atcoder agc031F所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(45)

评论列表共有 0 条评论

立即
投稿
返回
顶部