[CF780F]Axel and Marston in Bitland

\(\text{Problem}:\)Axel and Marston in Bitland

\(\text{Solution}:\)

记一条路径是好的,即:它的长度为 \(2^{k}\),且这段路径可以通过翻转(即将 \(P\) 变成 \(B\)\(B\) 变成 \(P\))如果是答案,它是合法的,即这段路径形如 \(PBBP\)\(BPPB\)。我们发现,好的路径当长度固定时,它的形式只和第一个字符是 \(P\) 或是 \(Q\) 有关。那么答案路径就可以表示成若干个好的路径按顺序拼接在一起,具体的,设答案路径长度为 \(len\),则有:

\(len=2^{k_{1}}(st.P)+2^{k_{2}}(st.B)+2^{k_{3}}(st.P)...,k_{1}>k_{2}>k_{3}...\)

\(F_{i,j,k,s}\) 表示从 \(i\)\(j\),是否存在长度为 \(2^{k}\),以 \(s\) 为第一条边的好路径,容易得到转移:

\(F_{i,j,k,s}|=(F_{i,x,k-1,s}\&F_{x,j,k-1,!s}),(1\leq x \leq n)\)

求答案时,我们从大到小枚举 \(k\),从满足当前条件的点,转移到满足 \(k\) 条件的点。如果点集不空,则更新点集,并且将 \(2^k\) 计入答案。

但是 \(F\) 转移的时间复杂度我们无法接受。考虑对于 \(F\) 的转移,都是位运算,故可以用 \(bitset\) 优化转移。

\(\text{Code}:\)

#include <bits/stdc++.h>
#pragma GCC optimize(3)
#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
using namespace std; const int N=505, M=60;
inline int read()
{
	int s=0, w=1; ri char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
	return s*w;
}
int n,m,Ans;
bitset<N> F[N][M+2][2],res,vis;
signed main()
{
	n=read(), m=read();
	for(ri int i=1;i<=m;i++)
	{
		int u,v,t;
		u=read(), v=read(), t=read();
		u--, v--;
		F[u][0][t].set(v);
	}
	for(ri int p=1;p<=61;p++)
	for(ri int i=0;i<n;i++)
	for(ri int j=0;j<n;j++)
	for(ri int k=0;k<2;k++)
	if(F[i][p-1][k][j])
	F[i][p][k]|=F[j][p-1][k^1];
	vis.set(0);
	int sta=0;
	for(ri int i=61;~i;i--)
	{
		res.reset();
		for(ri int j=0;j<n;j++) if(vis[j]) res|=F[j][i][sta];
		if(!(int)(res.count())) continue;
		vis=res;
		sta^=1, Ans+=(1ll<<i);
	}
	printf("%lld\n",(Ans>1e18)?(-1):(Ans));
	return 0;
}
posted @ 2021-02-22 14:03  zkdxl  阅读(72)  评论(1编辑  收藏  举报