線性基參考博客:
關於線性基的學習與理解
線性基詳解
題目:P3812 【模板】線性基
題意:給你一個數組,讓你任意選數,使異或和最大。
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int maxn = 100;
LL p[maxn];
void Insert(LL val){
for(int i = 55; i >= 0; i--){
if(val&(1ll<<i)){
if(p[i])val ^= p[i];
else {
p[i] = val;
break;
}
}
}
}
int main(){
int n;
LL v;
scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%lld", &v);
Insert(v);
}
LL ans = 0;
for(int i = 55; i >= 0; i--){
if((ans^p[i]) > ans)ans ^= p[i];
}
printf("%lld\n", ans);
return 0;
}
題目:2460: [BeiJing2011]元素
題意:給你一個序列,每個序列有兩個值,一個是序號,另外一個事價值,本題的題意是在序列中任選序列,使數列異或和不爲0,並且價值最大。
思路:本題思路就是把序列從大到小排列一個順序,然後就行現行基構造,在構造的過程中最終沒有變爲0,那麼結果就加上這個價值。
代碼:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100;
typedef long long LL;
pair<LL, LL>mp[1005];
LL p[maxn];
bool cmp(pair<LL, LL>a, pair<LL, LL>b){
return a.second > b.second;
}
int main(){
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++){
scanf("%lld %lld", &mp[i].first, &mp[i].second);
}
sort(mp, mp+n, cmp);
LL ans = 0;
//cout<<(1>>0&1)<<endl;
memset(p, 0, sizeof p);
for(int i = 0; i < n; i++){
LL v = mp[i].first;
for(int j = 63; j >= 0; j--){
if(v>>j&1){
if(p[j])v ^= p[j];
else {
p[j] = v;
ans += mp[i].second;
break;
}
}
}
}
printf("%lld\n", ans);
return 0;
}
題目:2115: [Wc2011] Xor
題意:就是給你一個圖讓你從1走到n的路徑的最大異或和,存在重邊和環。
思路:本題的思路就是隨便走一條1~n的路,然後再把環加進去,有回到上面的類型題了。
參考博客:BZOJ2115 [Wc2011] Xor
代碼:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int maxn = 1e5+10;
int h[maxn<<1], nex[maxn<<1], to[maxn<<1];
LL w[maxn<<1], p[100], vis[maxn], dis[maxn],circle[maxn<<1];
int tot = 0, cnt = 0, u, v;
LL val;
inline void add(int u, int v, LL val)//數組模擬鏈式前向星
{
to[tot] = v;
w[tot] = val;
nex[tot] = h[u];
h[u] = tot++;
}
inline void Insert(LL val)//線性基的構造
{
for(int i = 63; i >= 0; i-- )
{
if((val>>i)&1)
{
if(p[i])val ^= p[i];
else
{
p[i] = val;
break;
}
}
}
}
inline void dfs(int x)//搜索
{
vis[x] = 1;
for(int i = h[x]; ~i; i = nex[i])
{
int v = to[i];
LL val = w[i];
if(!vis[v])
{
dis[v] = dis[x]^val;//存儲這個路徑的異或和
dfs(v);
}
else
{
circle[cnt++] = dis[x]^dis[v]^val;//只保存環,所以異或上之前的點就把之前的異或和去掉,然後再異或上當前節點
}
}
}
int main()
{
int n, m;
tot = 0, cnt = 0;
scanf("%d %d", &n, &m);
memset(dis, 0, sizeof dis);
memset(h, -1, sizeof h);
for(int i = 1; i <= m; i++)
{
scanf("%d %d %lld", &u, &v, &val);
add(u, v, val);
add(v, u, val);
}
dfs(1);
LL ans = dis[n];
for(int i = 0; i < cnt; i++)
{
if(!circle[i])continue;
Insert(circle[i]);
}
for(int i = 63; i >= 0; i--)//找最大異或和
{
if((ans^p[i])>ans) ans ^= p[i];//注意(ans^p[i])>ans,一定要加括號,否就涼涼
}
printf("%lld\n", ans);
return 0;
}