[校内模拟]binary(状压DP)

本文介绍了一种使用位运算和动态规划解决特定问题的方法。通过将数字分为前后两部分进行处理,有效地降低了算法的时间复杂度。该方法适用于处理大规模数据集,尤其是在需要频繁更新和查询最大值的情况下。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

=== ===

这里写图片描述

=== ===

题解

学姐那次胡策的三道题全用的zyf当题面2333@zyf2000
(Update-两分钟后:zyf2000想要打击报复差点把上面那句话删掉!!!)
一开始还想用字典树搞来着。。但是字典树的话只是处理异或运算比较方便啊。。并且a的范围来讲O(n2)的复杂度也不大科学是吧。
然后就有了一个非常厉害的做法:把数字分成两部分去DP!
用f[i][j]表示出现过的前8位为i的数和某个后8位为j的数做题目中给定的位运算能得到的后8位的最大值,同时用g[i][j]记录方案数。
设当前操作数的前8位是a,后8位是b,插入数的时候枚举所有的j,用j和b的运算结果来更新f[a][j];计算答案的时候枚举所有出现过的i,用i和a的运算结果拼上f[i][b]来更新答案。这样的话因为28非常小啊所以时间复杂度也相当科学。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int Max=256;
int n,type,f[510][510],g[510][510],a[100010];
char opt[10];
bool ext[500];
int calc(int x,int y){
    switch (opt[0]){
        case 'a':return x&y;
        case 'o':return x|y;
        case 'x':return x^y;
    }
}
void update(int k){
    int a,b;
    a=k>>8;b=k-(a<<8);
    for (int i=0;i<=Max;i++){
        int dlt=calc(i,b);
        if (dlt>f[a][i]){
            f[a][i]=dlt;g[a][i]=1;
        }else
          if (dlt==f[a][i])
            ++g[a][i];
    }
    ext[a]=true;
}
void getans(int k){
    int a,b,ans1,ans2;
    a=k>>8;b=k-(a<<8);
    ans1=ans2=0;
    for (int i=0;i<=Max;i++)
      if (ext[i]==true){
          int dlt=(calc(i,a))<<8;
          dlt=dlt|f[i][b];
          if (dlt>ans1){ans1=dlt;ans2=g[i][b];}
          else if (dlt==ans1) ans2+=g[i][b];
      }
    if (type==0) printf("%d\n",ans1);
    else printf("%d %d\n",ans1,ans2);
}
int main()
{
    freopen("binary.in","r",stdin);
    freopen("binary.out","w",stdout);
    scanf("%d%s%d",&n,&opt,&type);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    update(a[1]);
    for (int i=2;i<=n;i++){
        getans(a[i]);
        update(a[i]);
    }
    return 0;
}

偏偏在最后出现的补充说明

如果直接把所有数字存在状态里的话65536*65536肯定卡飞对吧但是这样把它分成两部分来搞的话就非常科学了。关键在于利用位运算各位之间的独立性。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值