1. 程式人生 > >Born Slippy (超大背包問題 + 樹形DP)

Born Slippy (超大背包問題 + 樹形DP)

div color clas ans include memset long long pre pac

首先是需要我們知道的是假設又一條鏈給你讓你求最大值,你會求嗎?當然會,就是時間有點爆炸O(n2)。那不行,要是如果我把到達每個點的最大值以及他對後面的貢獻情況都求出來後放在數組裏面,然後到了新的節點直接查詢該點的情況,但是問題就在於我們存進數組的時候遍歷了O(1 << 16)那麽時間還是不可以過,這時候需要使用大背包的想法,我們只把後面8為的結果打出來並存進數組,然後查詢的時候只需要查詢前8位,這樣一來是不是時間就又優化到了允許的範圍內了。還有就是我在樹上面跑的時候會有重復的狀況,就是兩條鏈共用了同一套數據,那麽只需要記錄一下,然後回溯就可以便面這個問題了。

然後還有一個問題就是,我下載了數據,然後去跑一下,發現一個問題,就是我的電腦由於遞歸層數過多導致炸內存。所以就是買個大一點的內存可以更加為所欲為。

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

const int mod  = 1e9 + 7;
const int maxn = (1 << 16) + 7;
const int maxm = (1 << 8) + 7;
vector<int>vec[maxn];
LL tmp[maxn][maxm], dp[maxm][maxm], w[maxn], ans;
int vis[maxm];
char str[10];


int opt(int a, int
b){ if(str[0] == X) return a ^ b; if(str[0] == A) return a & b; if(str[0] == O) return a | b; } void dfs(int rt){ LL ret = 0; LL a = w[rt] >> 8; LL b = w[rt] & 255; for(int i = 0; i < 256; i ++) if(vis[i]) ret = max(ret, dp[i][b] + (opt(i, a) << 8
)); ans = (1LL * rt * (ret + w[rt]) + ans) % mod; vis[a] ++; for(int i = 0; i < 256; i ++) tmp[rt][i] = dp[a][i], dp[a][i] = max(dp[a][i], ret + opt(b, i)); for(int i = vec[rt].size() - 1; i >= 0; i --) dfs(vec[rt][i]); for(int i = 0; i < 256; i ++) dp[a][i] = tmp[rt][i]; vis[a] --; } int main(){ int T,n,rt;scanf("%d",&T); while(T --){ scanf("%d%s",&n, str);ans = 0; memset(dp, 0, sizeof(dp)); memset(vis, 0, sizeof(vis)); for(int i = 1; i <= n; i ++)scanf("%lld",&w[i]),vec[i].clear(); for(int i = 2; i <= n; i ++)scanf("%d",&rt),vec[rt].push_back(i); dfs(1);printf("%lld\n",ans); } return 0; }

Born Slippy (超大背包問題 + 樹形DP)