HDU5735 Born Slippy

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5735


【题意】有n个节点,节点i的权值是wi,对于一个节点队列v1,v2,.....,vm,其中节点vi是节点点v(i-1)的祖先。对于一个队列,满足v1=s,f(s)=wv1+i=2mwvi opt wvi1是最大的。求解=
S=(i=1nif(i))%(1e9+7)

【分析】先膜拜题解,采用题解神奇的暴力dfs方法。先定义一个dp[i]=max(dp[j]+wi opt wj)(j是i的祖先)。

那么f(s)=dp[s]+ws。设定一个二维数组ds(x,y)是某个wi的后8位是y,某个wj的前8位是x的时候,dp(j)+wi后8位 opt wj后8位

的最值,于是就可以从祖先开始暴力求解,每次先枚举所有可能的祖先前8位,获得当前节点的最大值,累加在答案中,

保存当前的ds值,再枚举所有可能的子孙后8位,以这个为子孙的后8位最大值,搜索子孙,返回后将保存的值赋回。


【代码】

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define LL long long
#define MAXN 65540
#define uint unsigned int
const int mod=1e9+7;
uint n,f,ans;
uint w[MAXN],vis[260],nxt[MAXN],ds[260][260],head[MAXN],tmp[MAXN][260];
char op[10];
void updata(uint &a,uint b){
    if(a<b)
        a=b;
}
int opt(uint a,uint b){
    if(op[0]=='A')
        return a&b;
    if(op[0]=='X')
        return a^b;
    return a|b;
}
void dfs(uint x){
    uint dp=0,a=w[x]>>8,b=w[x]&255;
    for(uint i=0;i<256;++i)
        if(vis[i])
            updata(dp,ds[i][b]+(opt(i,a)<<8));
    ans=(1LL*x*(dp+w[x])+ans)%mod;
    vis[a]++;
    for(uint i=0;i<256;++i){
        tmp[x][i]=ds[a][i];
        updata(ds[a][i],opt(i,b)+dp);
    }
    for(uint i=head[x];i;i=nxt[i])
        dfs(i);
    vis[a]--;
    for(uint i=0;i<256;++i)
        ds[a][i]=tmp[x][i];
}
int main(){
    uint T;
    cin>>T;
    while(T--){
        scanf("%d %s",&n,&op);
        for(int i=1;i<=n;++i){
            scanf(" %d",&w[i]);
            head[i]=0;
        }
        for(int i=2;i<=n;++i){
            scanf(" %d",&f);
            nxt[i]=head[f];
            head[f]=i;
        }
        ans=0;
        dfs(1);
        cout<<ans<<endl;
    }
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值