HDU 5735 Born Slippy(dp+优化)

树形dp

如果接暴力dp会超时,所以需要优化,dp[s]=max(dp[s],dp[i]+w[i] opt w[s]),其中i是s的祖先,那么暴力则是O(n^2)。

优化思路:

对于当前搜索到的点u,拥有数组ds(x,i),该数组储存ds(x,i)=max(dp[j]+ y opt i),其中x与y分别是j的前8位和后8位。

那么dp[u]=max(dp[u],ds(i,B)+((A opt i) << 8) ),就相当于预先计算了任意祖先j与后代可能出现的后八位的和并且对于相同前八位仅保留最值,后代计算dp时就可以枚举已经出现的前八位来利用这些信息。(文字表达能力差,具体看代码)


#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>

using namespace std;

#define ll unsigned int

const int maxn=(1<<16)+1;
const ll mod=1000000007;

ll f[256][256],ff[maxn][256],w[1000005];
int vis[256];
int head[1000005];
int ne[1000005];
int to[1000005];
int opt;

int cot;

void init(){
    cot=0;
    memset(head,-1,sizeof(head));
}

void addedge(int u,int v){
    to[cot]=v;
    ne[cot]=head[u];
    head[u]=cot++;
}

ll getv(ll a,ll b){
    if(opt==0)return a&b;
    else if(opt==1)return a|b;
    else return a^b;
}

ll ans;
void dfs(int u){
    ll A=w[u]>>8,B=w[u]&0x000000ff;
    ll dp=0,i;
    for(i=0;i<256;i++)if(vis[i])dp=max(dp,f[i][B]+(getv(i,A)<<8));
    ans=(ans+(1LL*(w[u]+dp)*u)%mod)%mod;
    for(vis[A]++,i=0;i<256;i++){
        ff[u][i]=f[A][i];
        f[A][i]=max(f[A][i],dp+getv(B,i));
    }
    for(i=head[u];~i;i=ne[i])dfs(to[i]);
    for(vis[A]--,i=0;i<256;i++)f[A][i]=ff[u][i];
}

char ch[3];
int main(){
    int t,n;
    int v;
    scanf("%d",&t);
    while(t--){
        init();
        scanf("%d %s",&n,ch);
        //printf("%d %s\n",n,ch);
        if(ch[0]=='A')opt=0;
        else if(ch[0]=='O')opt=1;
        else opt=2;
        for(int i=1;i<=n;i++)scanf("%u",&w[i]);
        for(int i=2;i<=n;i++){
            scanf("%d",&v);
            addedge(v,i);
        }
        ans=0;
        dfs(1);
        printf("%u\n",ans);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值