HDU 5735 Born Slippy

16 篇文章 0 订阅
11 篇文章 0 订阅

Description

Professor Zhang has a rooted tree, whose vertices are conveniently labeled by 1,2,...,n . And the i -th vertex is assigned with weight wi.For each s{1,2,...,n} , Professor Zhang wants find a sequence of vertices v1,v2,...,vm such that:1. v1=s and vi is the ancestor of vi1 (1<im) .2. the value f(s)=wv1+i=2mwvi opt wvi1 is maximum. Operation x opt y denotes bitwise AND,ORorXOR operation of two numbers.

Solution

比赛时根本不知所措。。
赛后看题解,orz出题人脑洞
首先显然dp
dp[i] 表示节点 i i=2mwvi opt wvi1的最大值
由定义 f[i]=dp[i]+w[i]
dp 的转移也是显然的: dp[i]=maxj is is ancestordp[j]+w[j] opt w[i]
关键是这个转移好像不好搞。。
标程给了一个类似meet in the middle的转移方法

先考虑序列上的简化问题
首先观察到题目的数据范围很奇怪
每个数字w[i]可以拆成 a<<8|b 的形式(即 a w[i]的前8位, b w[i]的后8位)。
定义 ds(i,x,y) 表示扫描到点 i ,某个之前的j w[j] 的前8位是 x w[i]的后8位是 y maxj<idp[j]+[w[j]8] opt [w[i]]8
然后你扫描到当前的 i ,知道了w[i]的前8位和后8位, O(28) 枚举之前 [w[j]8] ,即可简单转移。同样的,然后你可以 O(28) 地更新 ds 数组。
在树上和在序列上好像没差吧。。每个节点备份一下 ds 的状态回溯的时候还原现场即可。
当然, ds 的第一维是完全可以省掉的(滚掉),然后备份的空间复杂度为 O(28n) ,是可以过掉的。
感觉只搞过meet in the middle 的搜索题,这种出现在dp转移里的meet in the middle 也是极有借鉴价值的(看有一维直接消失了)。

Code

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef vector<int> vec;
typedef priority_queue<int> pq;

#define pb push_back
#define ph push
#define fi first
#define se second

template<class T>void Max(T &a,T b){if(a<b)a=b;}
template<class T>void Min(T &a,T b){if(a>b||a==-1)a=b;}
template<class T>void rd(T &a){
    a=0;char c;
    while(c=getchar(),!isdigit(c));
    do a=a*10+(c^48);
        while(c=getchar(),isdigit(c));
}
template<class T>void nt(T x){
    if(!x)return;
    nt(x/10);
    putchar(48+x%10);
}
template<class T>void pt(T x){
    if(!x)putchar('0');
    else nt(x);
}
const int M=65540;
const int N=260;
const int P=1e9+7;
typedef unsigned ud;
int n,w[M],fa[M];
ud ds[N][N],f[M][N];
struct Edge{
    int to,nxt;
}edge[M];
int head[M],tot_edge,flag;
inline void add_edge(int a,int b){
    edge[tot_edge]=(Edge){b,head[a]};
    head[a]=tot_edge++;
}
string opt;
inline int calc(ud a,ud b){
    if(!flag)return a&b;
    if(flag==1)return a|b;
    return a^b;
}
int ans,cnt[N];
template<class T>void Mod_add(T &a,T b){
    if((a+=b)>=P)a-=P;
}
void dfs(int v){
    ud dp=0;
    ud a=w[v]>>8,b=w[v]&255;
    for(ud x=0;x<256;++x){
        if(cnt[x])
            Max(dp,(ud){ds[x][b]+(calc(a,x)<<8)});
    }
    Mod_add(ans,(int){(1ll*v*(dp+w[v]))%P});
    for(ud x=0;x<256;++x){//后8位 
        f[v][x]=ds[a][x];
        Max(ds[a][x],calc(x,b)+dp);
    }
    ++cnt[a];
    for(int i=head[v];~i;i=edge[i].nxt)
        dfs(edge[i].to);
    --cnt[a];
    for(int i=0;i<256;++i)
        ds[a][i]=f[v][i];
}
inline void gao(){
    memset(head,-1,sizeof(head));
    tot_edge=0;
    cin>>n>>opt;
    for(int i=1;i<=n;++i)rd(w[i]);
    for(int i=2;i<=n;++i)rd(fa[i]),add_edge(fa[i],i);
    if(opt[0]=='A')flag=0;
    if(opt[0]=='O')flag=1;
    if(opt[0]=='X')flag=2;
    ans=0;
    dfs(1);
    pt(ans);
    putchar('\n');
}
//#define LOCAL
int main(){
#ifdef LOCAL
    freopen("data.in","r",stdin);
    freopen("data.out","w",stdout);
#endif
    int _;for(cin>>_;_--;)gao();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值