• 2016多校第二场 HDU5735 神一样的dp,,,


    可以先看一下多校的题解感受一下,,,

    题意:

    设dp[s]=f(s)-Ws;

    则很容易设置dp方程dp[i]=max( dp[j] + Wi pot Wj )( j<i )  pot代表一种操作

    显然硬来时间复杂度很高,因为是树形结构,dfs遍历的过程中有很多东西可以记录下来,所以想办法事先把dp[j]通通记录下来

    因为数据范围是216 我们设置一个数组ds[x][b],表示当祖先结点的权值的前八位为x,当前结点权值后八位为b时 ds[x][b]= max{dp[j]+(Wj的后八位)pot(Wi的后八位)}————A

     则

    dp[i]=max(dp[i] ,ds[x][y]+((x pot a)<<8));

    其中j代表祖先节点,i代表当前节点,a代表Wi的前八位,通过遍历0~255相当于遍历了所有的祖先节点的前八位,而当碰到祖先节点时就会进行更新dp[i] 的操作

    在更新完dp[i]之后再更新ds[x][y]具体看代码,当然有可能对于一个结点来说ds[x][y]更新取得的值并不是这个结点的祖先的值,这个问题可以因为给出的图是树形结构而比较方便解决

    总体来说就是用权值前八位即0~255的遍历代替了对于每一个祖先结点的遍历,让复杂度下降到(28n)然后就过题了

    再具体一点就是说ds[x][y]记录的是所有的祖先结点的前八位为x时A式的最大值,这就省去了几个前八位同时为x时节点之间的比较

    最后说一句,膜膜膜膜膜膜膜大神

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <map>
    #include <math.h>
    using namespace std;
    
    const int MOD = 1e9 + 7;
    const int N=1<<17;
    typedef long long ll;
    int t,n,op,vis[300],cnt;
    ll w[N],dx[300][300],unuse[N][300],ans;
    char ss[10];
    std::vector<ll>g[N];
    ll opt(ll a,ll b){
    if(op==1) return a^b;
    if(op==2) return a&b;
    if(op==3) return a|b;
    }
    void dfs(ll u){
     ll a=w[u]>>8,b=w[u]&255,dp=0;
     for(ll i=0;i<256;i++)
     if(vis[i]) dp=max(dp,dx[i][b]+(opt(a,i)<<8));//vis是为了记录当前节点的祖先中是否有前八位为i的
     ans=ans+(u*((dp+w[u])%MOD))%MOD;
     ans%=MOD;
    //cout<<ans<<endl;
     vis[a]++;//接下来要访问u的字数所以vis[a]++
     for(ll i=0;i<256;i++){
        unuse[u][i]=dx[a][i]; //将访问u之前的dx[a][i]记录下来,当u的子树访问完之后还原以消除u的影响
        dx[a][i]=max(dx[a][i],dp+opt(b,i));//对u的子树更新dx
     }
    
     for(int i=0;i<g[u].size();i++){
        ll v=g[u][i];
        dfs(v);
     }
     for(int i=0;i<256;i++)
        dx[a][i]=unuse[u][i];//还原dx
        vis[a]--;//表示u已经访问完它的前八位的vis减掉
    }
    int main()
    {
    //freopen("in.txt","r",stdin);
    cin>>t;
    while(t--){
       for(int i=0;i<N;i++)
          g[i].clear();
       memset(vis,0,sizeof(vis));
       memset(dx,0,sizeof(dx));
        scanf("%d",&n);
        getchar();
        scanf("%s",ss);
      // cout<<ss<<endl;
    
        if(ss[0]=='X') op=1;
        if(ss[0]=='A') op=2;
        if(ss[0]=='O') op=3;
        int i;
        for(i=1 ;i<=n; i++)
            scanf("%lld",&w[i]);
        for(i=2;i<=n;i++){
            ll j;
            scanf("%lld",&j);
            g[j].push_back(i);
        }
        ans=0;
       // cout<<"r"<<endl;
        dfs(1);
        cout<<ans<<endl;
     }
    
    return  0;
    }

    ancestor of imax​​{dp(j)+wi​​ and wj​​}. 然后, 显然dp(j)+wi and wjdp(j)+w_i ext{ and }w_jdp(j)+wi​​ and wj​​这个式子可以拆成dp(j)dp(j)dp(j)+[wiw_iwi​​后8位] and [wjw_jwj​​后8位] + ([wiw_iw​i​​前8位] and [wjw_jw​j​​前8位]) << 8.

     

    S=(ni=1if(i))mod(109+7).

    S=(ni=1if(i)) mod (109+7).

    2n216,0wi<216.

    2n216,0wi<216.

  • 相关阅读:
    正则表达式
    数据结构与算法-串
    数据结构与算法-优先级队列
    数据结构与算法-词典
    数据结构与算法-高级搜索树
    数据结构与算法-二叉搜索树
    数据结构与算法-图
    数据结构与算法-二叉树
    数据结构与算法-栈与队列
    数据结构与算法-列表
  • 原文地址:https://www.cnblogs.com/shimu/p/5706781.html
Copyright © 2020-2023  润新知