題目連接: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 wvi−1是最大的。求解
S=(∑i=1ni⋅f(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;
}
}