[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;
}
夜畔流离回,暗叹永无殿。
独隐万花翠,空寂亦难迁。
千秋孰能为,明灭常久见。
但得心未碎,踏遍九重天。