ps:最近碰到一些用bitset优化常数的题目,以前也有接触但是都没有记下来,所以来写一篇博文 记录以后碰到的类似的题目。
应用一: 优化boolean multiplication
在做dp的时候,有时候会需要将两个dp矩阵相乘,且矩阵的元素都是bool型。
计算矩阵A*B=C C[i,j]=1 当且仅当存在k,A[i,k]=1 && B[k][j]=1 。
直接算需要O(n3)的时间。可以用bitset 优化常数。 做法如下:
1 bitset<N> A[N],B[N],C[N]; 2 3 void Multi(bitset<N> A[],bitset<N> B[],bitset<N> C[]) 4 { 5 for (int i=0;i<N;i++) 6 { 7 for (int j=0;j<N;j++) 8 { 9 if (A[i][j]) C[i]|=B[j]; 10 } 11 } 12 }
大致思想是:
如果A[i][j]=1, C[i][k] |= A[i][j] & B[j][k] <-> C[i][k] |= B[j][k] 相当于把B的第j行拿去 和C的第i行做一次或操作。
题目:
http://codeforces.com/contest/781/problem/D
该题的dp矩阵是boolean矩阵,转移的时候可以用bitset来优化boolean multiplication。
1 #include <iostream> 2 #include <string> 3 #include <cstring> 4 #include <map> 5 #include <cmath> 6 #include <set> 7 #include <bitset> 8 using namespace std; 9 10 typedef long long ll; 11 12 #define N 510 13 14 bitset<N> dp[61][2][N]; 15 16 int main() 17 { 18 //freopen("in.in","r",stdin); 19 //freopen("out.out","w",stdout); 20 21 int n,m,x,y,z; 22 scanf("%d%d",&n,&m); 23 while (m--) 24 { 25 scanf("%d%d%d",&x,&y,&z); 26 x--,y--,dp[0][z][x][y]=1; 27 } 28 29 for (int l=1;l<=60;l++) 30 { 31 for (int i=0;i<n;i++) 32 { 33 for (int j=0;j<n;j++) 34 { 35 if (dp[l-1][0][i][j]) dp[l][0][i]|=dp[l-1][1][j]; 36 if (dp[l-1][1][i][j]) dp[l][1][i]|=dp[l-1][0][j]; 37 } 38 } 39 } 40 ll ans=0; set<int> S; S.insert(0); 41 for (int l=60,w=0;l>=0 && ans<=1e18;l--) 42 { 43 set<int> SS; 44 for (set<int>::iterator iter=S.begin();iter!=S.end();iter++) 45 { 46 int x=*iter; 47 for (int j=0;j<n;j++) if (dp[l][w][x][j]) SS.insert(j); 48 } 49 if (!SS.empty()) ans+=1ll<<l,S=SS,w^=1; 50 } 51 if (ans>1e18) ans=-1; 52 printf("%I64d ",ans); 53 return 0; 54 }
待补充...