牛客练习赛151

文章目录

  • [D 树形DP](#D 树形DP)
  • [E 区间异或和 哈希表 DP](#E 区间异或和 哈希表 DP)

D 树形DP

cpp 复制代码
const int N = 2e5+5,M=1e5;
const double PI=acos(-1);
const long long mod =998244353, inf = 1e18+10 ,up=1e9;
int dp[N][2];// dp[节点编号now][0:fa->now/1:now->fa]=now子树的out^2
vector<int>g[N];
void dfs(int now,int fa){
  /*
    从子节点向父节点递推 每个节点只有一个父亲 只关注到父亲的边方向
    怎么确定指向哪里最优?
    一开始设置所有的子节点都设置为指向当前节点now(dp[x][1]) 
    如果dp[x][0]-dp[x][1]很大 dp[x][1]+dp[x][0]-dp[x][1]=dp[x][0]那么指向x最优
  */
  vector<int>dis;// 子节点dp[0]-dp[1]
  int sm1=0;// sum of dp[x][1]
  for(auto x:g[now]){
    if(x==fa)continue;
    dfs(x,now);
    dis.push_back(dp[x][0]-dp[x][1]);
    sm1+=dp[x][1];// 0:指向本节点now 到父节点的边没有贡献 子节点x都指向now 
  }
  sort(dis.begin(),dis.end(),greater<int>());
  dp[now][0]=sm1,dp[now][1]=sm1+1;// out=1 只有now指向fa的一条边,now没有指向子节点x的
  int pre=0;
  forr(k,1,dis.size()){// 取前k条边
    pre+=dis[k-1];
    /* 之前写错了 dp[now][0]是会改变的
    dp[now][0]=max(dp[now][0],dp[now][0]+pre+k*k);
    dp[now][1]=max(dp[now][1],dp[now][0]+pre+(k+1)*(k+1));
    */
    dp[now][0]=max(dp[now][0],sm1+pre+k*k);//最大的k个边变成0------now指向孩子x 本节点的out=k
    dp[now][1]=max(dp[now][1],sm1+pre+(k+1)*(k+1));// 还有一条now指向fa out=k+1
  }
}
void solve(){
  int n;cin>>n;
  forr(i,1,n-1){
    int u,v;cin>>u>>v;
    g[u].push_back(v);
    g[v].push_back(u);
  }
  // 一条边只影响两个端点的贡献 可以枚举记录两种方向的结果取最大值
  dfs(1,0);// 因为是树结构 随便找一个点为根 这样就有了父子关系 关注指向父亲还是指向儿子
  cout<<dp[1][0]<<endl;//根节点1没有父节点 不指向父节点
}

E 区间异或和 哈希表 DP

出题人题解:

cpp 复制代码
map<int,int> hashmp[30][2];
void solve(){
  /*区间异或和
    目标:add sum>xor sum
    - 需要一个区间某位add_sum=1 xor_sum=0,那么区间全是1且长度是偶数
    - 在以上前提下,
      区间add_sum=1时 xor_sum必为0
      add_sum=0时 这一位不全为1 xor_sum=不确定
      为了满足目标 需要xor_sum=0 
    - 则 一个区间所有位的ADD_SUM最高位是H 那么XOR_SUM高于H位都为0
    - 目标就是找偶数长度区间的某一位k add_sum=1 并且所有高位xor_sum=0 prexor_i>>(k+1)=prexor_j>>(k+1)
  */
  int n;cin>>n;
  vector<int>a(n+1),prexor(n+1,0),dp(n+1,-1);// dp[i]=第i位之前最多分多少段
  
  forr(i,1,n)cin>>a[i],prexor[i]=prexor[i-1]^a[i];

  if(n&1)return cout<<-1<<endl,void();
  dp[0]=0;
  forr(i,1,n){// 遍历每个位置
    reforr(b,0,30){
      if(a[i]>>b&1){// 这一位是1 找到了目标位置
        if(dp[i-1]!=-1){// 和前面一个位置之间能划分 i-1作为上一个位置的结尾
          // 放入哈希表
          int highxor=prexor[i-1]>>(b+1);
          hashmp[b][(i-1)&1][highxor]=max(dp[i-1],hashmp[b][(i-1)&1][highxor]);
        }
        int now_highxor=prexor[i]>>(b+1);
        if(hashmp[b][i&1].count(now_highxor)){
          dp[i]=max(dp[i],hashmp[b][i&1][now_highxor]+1);
        }
      }else{// 这一位是0 肯定不能作为目标位置 如果保留历史值之后找到的也不合法 
        // 直接消除
        hashmp[b][1].clear();
        hashmp[b][0].clear();
      }
    }
  }
  cout<<dp[n]<<endl;
}
相关推荐
Ricardo-Yang2 小时前
# BPE Tokenizer:从训练规则到推理切分的完整理解
人工智能·深度学习·算法·机器学习·计算机视觉
qyzm2 小时前
牛客周赛 Round 140
数据结构·python·算法
Severus_black2 小时前
顺序表、单链表经典算法题分享(未完待续...)
c语言·数据结构·算法·链表
我不是懒洋洋2 小时前
【经典题目】栈和队列面试题(括号匹配问题、用队列实现栈、设计循环队列、用栈实现队列)
c语言·开发语言·数据结构·算法·leetcode·链表·ecmascript
Polaris_T3 小时前
2026最新字节大模型岗面经汇总(多平台整理)
人工智能·经验分享·算法·aigc·求职招聘
ghie90903 小时前
MATLAB 解线性方程组的迭代法
开发语言·算法·matlab
m0_743106463 小时前
【浙大&南洋理工最新综述】Feed-Forward 3D Scene Modeling(二)
人工智能·算法·计算机视觉·3d·几何学
Brilliantwxx3 小时前
【数据结构】排序算法的神奇世界(下)
c语言·数据结构·笔记·算法·排序算法
进击的荆棘3 小时前
递归、搜索与回溯——二叉树中的深搜
数据结构·c++·算法·leetcode·深度优先·dfs