【HDU 5735】Born Slippy(状压dp)

来源:互联网 发布:字符串数组结束标志 编辑:程序博客网 时间:2024/06/08 19:05

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

  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 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 (2n216,opt{AND,OR,XOR})– the number of vertices and the operation. The second line contains n integers w1,w2,...,wn (0wi<216). The thrid line contain n1 integers f2,f3,...,fn (1fi<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=1nif(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 wvi1
s{1,2,...,n}
v为自选的集合。满足v1=s 并且 vivi1的祖先2im (m为选择的节点数量)

最直白的想法:dpi=maxji{dpj+(a+A)<<8+(b+B)}
adpj前八位 Adpi前八位
bdpj后八位 Bdpj后八位
这样是n2的复杂度,当然不可行

考虑优化,将遍历一个节点时,内部更新的O(n)降下来。
wi为16位 考虑均拆为两部分 两个八位二进制。
这样考虑一个中间数组ds[x][y]表示之前所有祖先j中二进制前八位为x,当前位置wi二进制后八位为y时的最大值。(注意,这里暂不计入ij前八位操作的结果)

这样在计算dp[i]时。
枚举祖先二进制前八位,因为确定当前节点i后,其实ds数组第二维(wi的后八位)就已知了。
然后取遍历过程中ds[x][y]+(wioptx)<<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;}
0 0
原创粉丝点击