生活随笔
收集整理的這篇文章主要介紹了
【模板】线性基
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
ACM模板
文章目錄
學習線性基可考慮以下大佬博客
知乎Pecco博客
博客園Kaori博客
menci博客
肖然博客
從線性代數談線性基(有點硬核)
構造線性基
普通插入:
不能保證除了主元上其他線性基元素該位置為1
typedef unsigned long long ull
;
ull p
[64];
void insert(ull x
)
{for(int i
=63;i
>=0;i
--){if(!(x
>>i
&1)) continue;if(!p
[i
]) {p
[i
]=x
;break;}x
^=p
[i
];}
}
進階插入:
若p[i]!=0(即主元i存在),則線性基中只有p[i]的第i位是1;且此時p[i]的最高位就是第i位
bool insert(ll x
)
{for(int i
=62;i
>=0;i
--){if(!(x
>>i
&1)) continue;if(p
[i
]){x
^=p
[i
];continue;}for(int j
=i
-1;j
>=0;j
--)if(x
>>j
&1) x
^=p
[j
];for(int j
=62;j
>i
;j
--)if(p
[j
]>>i
&1) p
[j
]^=x
;p
[i
]=x
;return 1;}return 0;
}
線性基模板操作
1.在一系列數中選若干數做異或,求最大值。
反向遍歷p[]數組,按高位貪心(因為對于每個p[i]來說,當且僅當目前的res的第i位為0時,選這個數可以使res增大。而此時,選它一定比不選它更優)
普通插入代碼:
ull
getmax()
{ull res
=0;for(int i
=63;i
>=0;i
--)if((res
^p
[i
])>res
) res
^=p
[i
];return res
;
}
進階插入:直接把所有p[i]異或即是最大值。
2.在一系列數中選若干數做異或,求最小值。
直接求線性基,然后選最小的一個即可。顯然它與線性基中任意其他數異或后,都不會更小。
注意:特判0
普通插入代碼:
ull
getmin()
{if(cnt0
) return 0;for(int i
=0;i
<=63;i
++)if(p
[i
]) return p
[i
];
}
進階插入:找到最小主元即可
3.查詢某數是否能被表示出來
按照插入的思路進行檢查即可。
bool belong(ull x
)
{for(int i
=63;i
>=0;i
--){if(!(x
>>i
&1)) continue;if(!p
[i
]) return false;x
^=p
[i
];}return true;
}
4.查詢第k小值
使用進階插入解決此問題,把k進行二進制分解,把1對應位置的主元xor起來。
注意:第0小是0
ll now
[64];
int cnt
=0;
for(int i
=0;i
<=62;i
++)if(p
[i
]) now
[cnt
++]=p
[i
];
ll
query(ll k
)
{if(flag
) k
--;if(!k
) return 0;if(k
>=(1ull<<cnt
)) return -1;ll res
=0;for(int i
=0;i
<cnt
;i
++)if(k
>>i
&1) res
^=now
[i
];return res
;
}
線性基相關題目
【模板】線性基
普通插入即可解決
#include<iostream>
#include<algorithm>
using namespace std
;
typedef long long ll
;
typedef unsigned long long ull
;
const int N
=70;
ull p
[N
];
int n
;
void insert(ull x
)
{for(int i
=63;i
>=0;i
--){if(!(x
>>i
&1)) continue;if(!p
[i
]) {p
[i
]=x
;break;}x
^=p
[i
];}
}
int main()
{cin
>>n
;for(int i
=1;i
<=n
;i
++) {ull x
;cin
>>x
;insert(x
);}ull res
=0;for(int i
=63;i
>=0;i
--)if((res
^p
[i
])>res
) res
^=p
[i
];cout
<<res
<<'\n';return 0;
}
異或運算
第k異或小,使用進階插入即可解決。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std
;
typedef long long ll
;
typedef unsigned long long ull
;
const int N
=10010;
ll p
[70];
int n
,q
;
bool flag
;
ll now
[70];
int cnt
;
bool insert(ll x
)
{for(int i
=62;i
>=0;i
--){if(!(x
>>i
&1)) continue;if(p
[i
]){x
^=p
[i
];continue;}for(int j
=i
-1;j
>=0;j
--)if(x
>>j
&1) x
^=p
[j
];for(int j
=62;j
>i
;j
--)if(p
[j
]>>i
&1) p
[j
]^=x
;p
[i
]=x
;return 1;}return 0;
}
ll
query(ll k
)
{if(flag
) k
--;if(!k
) return 0;if(k
>=(1ull<<cnt
)) return -1;ll res
=0;for(int i
=0;i
<cnt
;i
++)if(k
>>i
&1) res
^=now
[i
];return res
;
}
int main()
{int T
;cin
>>T
;for(int ca
=1;ca
<=T
;ca
++){printf("Case #%d:\n",ca
);memset(p
,0,sizeof p
);flag
=0;cnt
=0;cin
>>n
;for(int i
=1;i
<=n
;i
++){ll x
;cin
>>x
;if(!insert(x
)) flag
=1;}cin
>>q
;for(int i
=0;i
<=62;i
++)if(p
[i
]) now
[cnt
++]=p
[i
];while(q
--){ll k
;cin
>>k
;cout
<<query(k
)<<'\n';}}return 0;
}
[BJWC2011]元素
按照magic逆序,然后線性基插入
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std
;
typedef long long ll
;
typedef pair
<int,int> pii
;
typedef unsigned long long ull
;
const int N
=1010;
ull p
[N
];
struct node
{ll id
,w
;bool operator<(const node
& o
) const {return w
>o
.w
;}
}q
[N
];
int n
;
bool insert(ull x
)
{for(int i
=63;i
>=0;i
--){if(!(x
>>i
&1)) continue;if(!p
[i
]) return p
[i
]=x
,1;x
^=p
[i
];}return 0;
}
int main()
{IO
;int T
=1;while(T
--){cin
>>n
;for(int i
=1;i
<=n
;i
++) cin
>>q
[i
].id
>>q
[i
].w
;sort(q
+1,q
+1+n
);ll res
=0;for(int i
=1;i
<=n
;i
++){if(insert(q
[i
].id
)) res
+=q
[i
].w
;}cout
<<res
<<'\n';}return 0;}
Good subset
線性基+線段樹題解
搜索題解
2020/09/30 要加油哦~
總結
以上是生活随笔為你收集整理的【模板】线性基的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。