=== ===
这里放传送门
=== ===
题解
可以发现这个串它有一些特点,首先它的长度是2的幂,并且它是一个正串接着一个反串那种类型,正串的开头肯定是1,反串的开头肯定是0。那么可以用
f[i][j][k][l]
表示当前是在递推以1开头的串还是0开头的串/长度为2的几次幂/起点是
k
/终点是
判断无解的话就是最后如果存在
260
的合法路径就就输出-1,否则就开始构造答案。构造答案的过程是从高位到低位贪心地依次判断这一位能不能加进去,就是开一个bitset表示前面更高的那些位弄完了以后哪些点是可行的终点,一开始只有1号点一个点是可行的。然后每一位的时候枚举所有的点,如果这个点是可行的终点说明这个点后面还能接上一段路。最后如果这一位存在可行方案就把这一位加进去。
代码
#include<bitset>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const long long inf=1e18;
int n,m,now;
long long ans,bin[70];
bitset<510> f[2][63][510],g,tmp;
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
f[z][0][x][y]=1;//初值按照每一条边赋值
}
for (int i=1;i<=60;i++)
for (int j=1;j<=n;j++)
for (int k=1;k<=n;k++){
if (f[0][i-1][j][k]!=0) f[0][i][j]|=f[1][i-1][k];
if (f[1][i-1][j][k]!=0) f[1][i][j]|=f[0][i-1][k];
}
if (f[0][60][1].count()){
printf("-1\n");return 0;
}//先判断一下是否无解
now=0;tmp[1]=1;bin[0]=1;
for (int i=1;i<=60;i++) bin[i]=bin[i-1]*2;
for (int i=60;i>=0;i--){
g.reset();
for (int j=1;j<=n;j++)
if (tmp[j]) g|=f[now][i][j];
if (g.count()!=0){//如果当前位可行就记录答案
now^=1;tmp=g;ans|=bin[i];
}
}
if (ans>inf) printf("-1\n");//注意输出的时候也要判断一下
else printf("%I64d\n",ans);
return 0;
}