您的位置:首页 > 其它

【HDU 5735】Born Slippy(状压dp)

2016-07-25 16:54 316 查看
【HDU 5735】Born Slippy(状压dp)

Born Slippy

Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 833 Accepted Submission(s): 252

Problem 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:

v1=s and vi is the ancestor of vi−1(1<i≤m).

the value f(s)=wv1+∑i=2mwvi opt wvi−1 is maximum. Operation x opt ydenotes bitwise AND, OR or XOR operation of two numbers.

Input

There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:

The first line contains an integer n and a string opt (2≤n≤216,opt∈{AND,OR,XOR})– the number of vertices and the operation. The second line contains n integers w1,w2,...,wn (0≤wi<216). The thrid line contain n−1 integers f2,f3,...,fn (1≤fi<i), where fi is the father of vertex i.

There are about 300 test cases and the sum of n in all the test cases is no more than 106.

Output

For each test case, output an integer S=(∑i=1ni⋅f(i))mod(109+7).

Sample Input

3

5 AND

5 4 3 2 1

1 2 2 4

5 XOR

5 4 3 2 1

1 2 2 4

5 OR

5 4 3 2 1

1 2 2 4

Sample Output

91

139

195

Author

zimpha

Source

2016 Multi-University Training Contest 2

题目大意:

给出一棵树,每个点有点权。

定义f(s)=wv1+∑i=2mwvi opt wvi−1

s∈{1,2,...,n}

v为自选的集合。满足v1=s 并且 vi为vi−1的祖先2≤i≤m (m为选择的节点数量)

最直白的想法:dpi=maxj为i的祖先{dpj+(a+A)<<8+(b+B)}

a为dpj前八位 A为dpi前八位

b为dpj后八位 B为dpj后八位

这样是n2的复杂度,当然不可行

考虑优化,将遍历一个节点时,内部更新的O(n)降下来。

因wi为16位 考虑均拆为两部分 两个八位二进制。

这样考虑一个中间数组ds[x][y]表示之前所有祖先j中二进制前八位为x,当前位置wi二进制后八位为y时的最大值。(注意,这里暂不计入i和j前八位操作的结果)

这样在计算dp[i]时。

枚举祖先二进制前八位,因为确定当前节点i后,其实ds数组第二维(wi的后八位)就已知了。

然后取遍历过程中ds[x][y]+(wi前八位optx)<<8取最大值,即为dp[i]

这也是ds[x][y]不计前八位操作结果的原因。

这样通过dp[i]又可以更新ds[x][y] 其实此时i(以后遍历的节点的祖先)的前八位x又变成了已知的,枚举此时子孙可能的后八位,更新即可。

(不计后八位运算)

代码如下:

#include <iostream>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <list>
#include <algorithm>
#include <map>
#include <set>
#define LL long long
#define Pr pair<int,int>
#define fread(ch) freopen(ch,"r",stdin)
#define fwrite(ch) freopen(ch,"w",stdout)

using namespace std;
const int INF = 0x3f3f3f3f;
const int msz = 1<<8;
const int mod = 1e9+7;
const double eps = 1e-8;

struct Edge
{
int v,next;
};

LL ds[256][256];
LL dp[66666];
bool vis[66666];
Edge eg[66666];
int head[66666];
int cf[66666][2];
LL val[66666];
LL mp[65537][256];
LL ans;
int tp;

void Add(int u,int v)
{
eg[tp].v = v;
eg[tp].next = head[u];
head[u] = tp++;
}

void dfs(int u,int opt)
{
int a,b;
a = cf[val[u]][0];
b = cf[val[u]][1];
dp[u] = 0;
for(int i = 0; i < msz; ++i)
{
if(ds[i][b] == -1) continue;
if(opt == 0) dp[u] = max(dp[u],1LL*(ds[i][b]+((i&a)<<8)));
else if(opt == 1) dp[u] = max(dp[u],1LL*(ds[i][b]+((i|a)<<8)));
else if(opt == 2) dp[u] = max(dp[u],1LL*(ds[i][b]+((i^a)<<8)));
}

ans = (ans+(1LL*dp[u]*u)%mod)%mod;
//printf("dp[%d] %lld\n",u,dp[u]);
int v;

memcpy(mp[u],ds[a],sizeof(ds[a]));

int k;
for(int i = 0; i < msz; ++i)
{
if(opt == 0) k = i&b;
else if(opt == 1) k = i|b;
else if(opt == 2) k = i^b;
if(ds[a][i] == -1) ds[a][i] = dp[u]+k;
else ds[a][i] = max(1LL*ds[a][i],dp[u]+k);
}

for(int i = head[u]; i != -1; i = eg[i].next)
{
v = eg[i].v;
//    printf("%d-%d\n",u,v);
dfs(v,opt);
}

memcpy(ds[a],mp[u],sizeof(mp[u]));
}

int main()
{

int a,b,tmp;
a = 0;
b = 0;
while(a+b < 66666)
{
cf[a+b][0] = a>>8;
cf[a+b][1] = b;
//    if(a+b >= 4350 && a+b <= 4360)
//    printf("%d %d %d\n",a+b,cf[a+b][0],cf[a+b][1]);
b++;
tmp = b>>8;
tmp <<= 8;
a += tmp;
b -= tmp;
}

int t,u,n;

scanf("%d",&t);
char opt[5];

while(t--)
{
scanf("%d%s",&n,opt);

ans = 0;
for(int i = 1; i <= n; ++i)
{
scanf("%lld",&val[i]);
ans = (ans+1LL*val[i]*i)%mod;
}

memset(head,-1,sizeof(head));
tp = 0;
for(int i = 2; i <= n; ++i)
{
scanf("%d",&u);
Add(u,i);
}

memset(ds,-1,sizeof(ds));
if(opt[0] == 'A') dfs(1,0);
else if(opt[0] == 'O') dfs(1,1);
else dfs(1,2);

printf("%lld\n",ans);
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: