牛客練習賽37 C 筱瑪的迷陣探險(Trie+折半)

題目鏈接:

筱瑪的迷陣探險

 

題意:

一個n×n的矩陣A,每個格子上有一個有一個數Ai,j。入口在左上角的(1,1)處,出口在右下角的(n,n)處。每一步都只能向下或向右移動一格。最後能獲得的經驗值爲初始經驗e與路徑上經過的所有數的權值異或和。求筱瑪最大可能獲得的經驗值。

 

思路:

如果純暴力,dfs整張圖,複雜度O(2^(2n)),數量級最壞情況下爲O(2^40),肯定會TLE。

但如果只暴力搜半張圖,最壞爲O(2^20),時間沒有問題。因此,我們先從(1,1)開始dfs暴力遍歷上半張圖(上半部分,以對角線(從右上到左下)爲分割線),對角線上的每個點開一棵字典樹,存到這個點的所有可能情況。然後我們再從(n,n)開始暴力遍歷下半張圖,每當搜到對角線上的點時就去該字典樹上求異或最大值(複雜度O(logk)= 31,k爲字典樹節點個數),取所有最大值中的最大值。

總複雜度O(2^20 * logk)

注意:字典樹的空間大小儘可能大,這題有毒......

 

Code:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int MAX = 5e6+10;

int n;
ll e;
ll mp[25][25];
int tree[25][MAX][2];
int tot=0;
ll ans=0;

void add(int id,ll x)
{
    int root=0;
    for(int i=30;i>=0;i--){
        int p=(x>>i)&1;
        if(!tree[id][root][p])  tree[id][root][p]=++tot;
        root=tree[id][root][p];
    }
}

ll query(int id,ll x)
{
    int root=0;
    ll val=0;
    for(int i=30;i>=0;i--){
        int p=(x>>i)&1;
        if(tree[id][root][p^1]){
            val+=(1ll<<i);
            root=tree[id][root][p^1];
        }
        else{
            root=tree[id][root][p];
        }
    }
    return val;
}

void dfs1(int x,int y,int step,ll val)
{
    if(step==n){
        add(x,val^mp[x][y]);
        return;
    }
    if(y+1<=n)  dfs1(x,y+1,step+1,val^mp[x][y]);
    if(x+1<=n)  dfs1(x+1,y,step+1,val^mp[x][y]);
}

void dfs2(int x,int y,int step,ll val)
{
    if(step==n){
        ans=max(ans,query(x,val));
        return;
    }
    if(y-1>=1)  dfs2(x,y-1,step+1,val^mp[x][y]);
    if(x-1>=1)  dfs2(x-1,y,step+1,val^mp[x][y]);
}

int main()
{
    scanf("%d%lld",&n,&e);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            scanf("%lld",&mp[i][j]);
    tot=0;
    ans=0;
    dfs1(1,1,1,e);
    dfs2(n,n,1,0);
    printf("%lld\n",ans);
    return 0;
}

 

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