bzoj 5285: [Hnoi2018]寻宝游戏

本文介绍了一种处理二进制矩阵的操作算法,通过将输入的二进制数转化为矩阵并进行特定操作来解决问题。文章详细阐述了如何通过比较二进制数与操作序列来确定最终结果,并给出了具体的实现代码。

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

Description

1146405-20180418105150845-205382304.png

Solution

把输入的 \(n\) 个二进制数看作一个大小为 \(n*m\) 的矩阵
把每一列压成一个二进制数,其中最高位是最下面的元素
然后就有了 \(m\) 个二进制数 \(b_i\),然后逐位考虑

我们把操作序列也变成一个二进制数 \(x\),\(1\)\(\&\),\(0\)\(|\)
那么第 \(i\) 位最后的结果为 \(1\) 当且仅当 \(x<b_i\) (注意最高位是最下面的元素)

然后就是确定 \(x\) 的取值范围了
如果我们把 \(b\) 数组从大到小排序,如果确定了 \(x\) ,那么就相当与把 \(b\) 从某个地方断开,前面的二进制位变成 \(1\),后面的变成 \(0\)

考虑每一个询问: \(r_i\)
首先满足条件的情况一定是:在 \(b\) 数组中,\(r\) 中所有的 \(1\) 位都在 \(0\) 位前面

找到断点 \(i\) 之后,答案就是 \(b[i-1]-b[i]\)

#include<bits/stdc++.h>
using namespace std;
const int N=5010,mod=1000000007;
int n,m,Q,p[N];char s[N];
struct data{
    bool b[1010];int id;
    inline bool operator <(const data &p)const{
        for(int i=n;i>=1;i--)
            if(b[i]!=p.b[i])return b[i]>p.b[i];
        return id<p.id;
    }
}a[N];
bool w[N];
inline int putans(int x){
    int ret=0,t=0;
    for(int i=n;i>=1;i--)
        ret=(1ll*ret*2+a[x-1].b[i])%mod;
    for(int i=n;i>=1;i--)
        t=(1ll*t*2+a[x].b[i])%mod;
    ret=(ret-t+mod)%mod;
    return ret+(x==1);
}
int main(){
  freopen("hunt.in","r",stdin);
  freopen("hunt.out","w",stdout);
  cin>>n>>m>>Q;
  for(int i=1;i<=n;i++){
      scanf("%s",s+1);
      for(int j=1;j<=m;j++)a[j].b[i]=s[j]-'0';
  }
  for(int i=1;i<=m;i++)a[i].id=i;
  sort(a+1,a+m+1);
  for(int i=1;i<=m;i++)p[a[i].id]=i;
  for(int i=1;i<=n;i++)a[0].b[i]=1;
  while(Q--){
      scanf("%s",s+1);
      for(int i=1;i<=m;i++)w[p[i]]=s[i]-'0';
      bool t=0,flag=0;
      for(int i=1;i<=m;i++){
          if(t && w[i]){flag=1;break;}
          t=w[i]^1;
      }
      if(flag)puts("0");
      else{
          for(int i=1;i<=m+1;i++){
              if(w[i]==0){
                  printf("%d\n",putans(i));
                  break;
              }
          }
      }
  }
  return 0;
}

转载于:https://www.cnblogs.com/Yuzao/p/8872820.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值