您的位置:首页 > 其它

HDU 5735 Born Slippy

2016-07-24 16:54 351 查看
转载声明:http://blog.csdn.net/fsss_7/article/details/51999555(分析)

转载声明:http://blog.csdn.net/miracle_ma/article/details/52003773(参考代码)

题意:给定n个节点的一棵树, 每个节点都有权值, 现在s起点 ∈{1,2,3,4,5…n},

然后设 v1=s, 那么函数 f(s)=Wv1+∑(i=2)(m)Wvi opt Wvi-1 求的是以s为起点,祖先节点,组成一个序列使 f(s)最大,(这时的v2,v3..都还没确定的!) 不过所决定的序列(v1 < v2 < v3..( <代表右边顶点是左边的祖先)),然后输出S=(∑(i=1)(n) i*f(i))mod(1e9+7);

个人感觉:

推荐这两篇文章,第一篇文章题解,一看就几乎懂了..第二篇文章的推荐只是因为代码写得没那么晦涩难懂,我参考第二篇的代码+第一篇的代码理解而写出来..我也自己写写我的理解加深一下.

看到这道题,我们很容易就可以退出dp方程 dp[i]=max{dp[j]+wi opt wj} (j是i的父亲节点),如果按照这样子做dp的话,必然会超时(可以参考我的超时代码,很朴素的写法)

那么怎么优化呢,,这技巧我也没想过,反正我也不知道它的来历

首先我们设 w[i]=(a<<8) + b;(分成高8位和低8位)

那么转移方程就编程 dp[i]=max{dp[j]+(ai opt aj) + (bi opt bj) } 可是这样也没什么用啊,重头戏来了

我们先考虑一下,当前 w[i],会给后辈点带来什么影响,因为我们知道 后辈点的低8位在0-255的范围内,

我们设 f[a][b]=max{dp[i]+bi opt b}( b代表0-255) 那么我们就可以不管后辈点 低8位的关系,

假设当前 后辈点 为j , 那么我们只要枚举搞8位就可以得出答案了 此时 dp【j】=max{f[a][bj]+a opt aj}{a代表0-255)的所有高位就好了,

一定要!!注意a要存在才可能枚举呢,!因为这道样做法存在回溯,当前求出来的f在回溯的时候就不适用了,所以我们得用个Back保留一下这次的f才能对当前适用,具体看看代码咯.

分析:树形dp+ 优化

AC代码:

/* Author:GavinjouElephant
* Title:
* Number:
* main meanning:
*
*
*
*/

//#define OUT
#include <iostream>
using namespace std;
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <sstream>
#include <cctype>
#include <vector>
#include <set>
#include <cstdlib>
#include <map>
#include <queue>
//#include<initializer_list>
//#include <windows.h>
//#include <fstream>
//#include <conio.h>
#define MaxN 0x7fffffff
#define MinN -0x7fffffff
#define Clear(x) memset(x,0,sizeof(x))
typedef long long ll;
const int INF=0x3f3f3f3f;
const int mod=1e9+7;
const int maxn=(1<<16)+5;
const int maxm=(1<<8)+5;
ll w[maxn];
ll f[maxm][maxm];
ll dp[maxn];
ll Back[maxn][maxm];
vector<int> G[maxn];
string op;
int T;
int N;
int opt(int a,int b)
{
if(op[0]=='A') return a&b;
if(op[0]=='X') return a^b;
return a|b;
}
void dfs(int u)
{
ll tmp=0;
int a=w[u]>>8;
int b=w[u]&255;
for(int i=0;i<256;i++)
{
if(f[i][b]!=-1) tmp=max(tmp,f[i][b]+(opt(i,a)<<8));
}
dp[u]=w[u]+tmp;

for(int j=0;j<256;j++)
{
Back[u][j]=f[a][j];
}
for(int j=0;j<256;j++)
{
f[a][j]=max(f[a][j],tmp+(opt(b,j)));
}

for(int j=0;j<G[u].size();j++)
{
dfs(G[u][j]);
}
for(int j=0;j<256;j++) f[a][j]=Back[u][j];

}
int main()
{
#ifdef OUT
freopen("coco.txt","r",stdin);
freopen("lala.txt","w",stdout);
#endif
scanf("%d",&T);
while(T--)
{
scanf("%d",&N);
cin>>op;
for(int i=1;i<=N;i++)
{
scanf("%I64d",&w[i]);
G[i].clear();
}
for(int i=2;i<=N;i++)
{
int x;
scanf("%d",&x);
G[x].push_back(i);
}
memset(f,-1,sizeof(f));
memset(dp,0,sizeof(dp));
dfs(1);
ll ans=0;
for(int j=1;j<=N;j++)
{
ans=(ans+j*dp[j])%mod;
}
printf("%I64d\n",ans);

}
return 0;
}


朴素超时代码:

/* Author:GavinjouElephant
* Title:
* Number:
* main meanning:
*
*
*
*/

//#define OUT
#include <iostream>
using namespace std;
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <sstream>
#include <cctype>
#include <vector>
#include <set>
#include <cstdlib>
#include <map>
#include <queue>
//#include<initializer_list>
//#include <windows.h>
//#include <fstream>
//#include <conio.h>
#define MaxN 0x7fffffff
#define MinN -0x7fffffff
#define Clear(x) memset(x,0,sizeof(x))
typedef long long ll;
const int INF=0x3f3f3f3f;
int T;
int N;
const int maxn=1e5;
const int mod=1e9+7;
string str;
int f[maxn];
int w[maxn];
ll dp[maxn];
int opt(int a,int b)
{
if(str[0]=='A') return a&b;
if(str[0]=='O') return a|b;
return a^b;
}
void init()
{
memset(f,-1,sizeof(f));
memset(dp,0,sizeof(dp));
}
ll V(int s)
{
int tmp=f[s];
while(tmp!=-1)
{
dp[s]=max(dp[s],dp[tmp]+opt(w[s],w[tmp]));
tmp=f[tmp];
//cout<<tmp<<endl;
}
return dp[s];
}
int main()
{
#ifdef OUT
freopen("coco.txt","r",stdin);
freopen("lala.txt","w",stdout);
#endif
scanf("%d",&T);
while(T--)
{
init();
scanf("%d",&N);
cin>>str;

ll ans=0;
for(int i=1;i<=N;i++) scanf("%d",&w[i]);

for(int i=2;i<=N;i++)
{
scanf("%d",&f[i]);
}

for(int i=1;i<=N;i++)
{
ans+=(i*(w[i]+V(i)))%mod;
}
printf("%I64d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: