Axel and Marston in Bitland[CF-780F][矩乘倍增,bitset優化]

文章目錄

題目

給定一張有向圖(可能有自環,保證沒有相同類型的重邊),每條邊有兩種類型,分別爲1或者0 從1開始走,要求走過的路徑類型成如下方式

0
01
0110
01101001

ii 個是由第 i1i-1 個和第 i1i-1 個取反拼在後面, 求最長路。

如果最長路長度大於 101810^{18} 輸出 1-1

1n500,1m2n21\le n\le 500,1\le m \le 2\cdot n^2

思路

我們定義
f[k][01][u][v]f[k][0|1][u][v] 表示是否存在 uuvv 的長度爲 2k2^k 的如題目所述的路徑( 11 爲取反路徑)
然後我們知道,如果將這個狀態後面兩維表示成鄰接矩陣,可以用矩乘來轉移,有
f[k][0]=f[k1][0]f[k1][1]f[k][1]=f[k1][1]f[k1][0] f[k][0]=f[k-1][0]*f[k-1][1]\\ f[k][1]=f[k-1][1]*f[k-1][0]
然後有一個套路

for(int i=1;i<=A.r;i++)
	for(int j=1;j<=B.c;j++)
		for(int k=1;k<=A.c;k++)
			C[i][j]+=A[i][k]*B[k][j];

我們知道是個矩乘都是這樣寫的
但是這裏鄰接矩陣我們還可以這樣寫

for(int i=1;i<=A.r;i++)
	for(int k=1;k<=A.c;k++)
		if(A[i][k])
			C[i]|=B[k];

這裏 A,B,CA,B,C 均爲 bitsetbitset 它的含義也非常直觀不講了
然後倍增跑跑就行了

#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<queue>
#include<deque>
#include<cstdio>
#include<bitset>
#include<vector>
#include<climits>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
#define ULL unsigned long long
using namespace std;
int read(){
 	int x=0,y=0;char c=getchar();
    while(c<'0'||'9'<c) c=getchar();
  	while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
   	return x;
}
#define Log 61
#define MAXN 500
#define INF 0x3f3f3f3f
int n,m;
struct Matrix{
	int r,c;
	bitset<MAXN> a[MAXN+5];
	bitset<MAXN>& operator [] (int x){return a[x];}
	void Init(int R,int C){
		r=R,c=C;
		for(int i=1;i<=r;i++)
			a[i].reset();
		return ;
	}
	friend Matrix operator * (Matrix A,Matrix B){
		Matrix C;
		C.Init(A.r,B.c);
		for(int i=1;i<=A.r;i++)
			for(int k=1;k<=A.c;k++)
				if(A[i][k])
					C[i]|=B[k];
		return C;	
	}
}f[Log+5][2],a,b;//f[k][0|1][u][v]:2^k 步 u 能否到 v 
int main(){
	n=read(),m=read();
	f[0][0].Init(n,n),f[0][1].Init(n,n);
	for(int i=1;i<=m;i++){
		int u=read(),v=read(),p=read();
		f[0][p][u][v]=1;
	}
	for(int k=1;k<=Log;k++){
		f[k][0]=f[k-1][0]*f[k-1][1];
		f[k][1]=f[k-1][1]*f[k-1][0];	
	}
	int opt=0;
	LL ans=0;
	a.Init(1,n),a[1][1]=1;
	for(int k=Log;k>=0;k--){
		b=a*f[k][opt];
		if(b[1].count()){
			a=b,opt^=1;
			ans+=(1ll<<k);
		}
		if(ans>(LL)1e18){
			puts("-1");
			return 0;
		}
	}
	printf("%lld\n",ans);
    return 0;
}

思考

學習到重定義 [ ][\ ] 的方法,高興
以後記住鄰接矩陣轉移 bitsetbitset 優化

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章