• 【洛谷4424】[HNOI/AHOI2018] 寻宝游戏(位运算思维题)


    点此看题面

    大致题意: 给你(n)(m)位二进制数。每组询问给你一个(m)位二进制数,要求你从(0)开始,依次对于这(n)个数进行(and)(or)操作,问有多少种方案能够得到给你的这个二进制数。

    找规律

    不难想到去对每一位分别讨论。

    则根据位运算法则可得:

    • 当你把某一位的数(and 0),就相当于把这一位数赋值为(0)
    • 当你把某一位的数(or 1),就相当于把这一位数赋值为(1)
    • 当你把某一位的数(and 1)或者(or 0)时,这一位的值均不变。

    则可以得出一个结论:

    • 若给定数这一位为(0),则对于这一位的运算中最后一次(and 0)要出现在最后一次(or 1)之后(或者两者都未出现)。
    • 若给定数这一位为(1),则对于这一位的运算中最后一次(or 1)要出现在最后一次(and 0)之后(注意(or 1)必须有,(and 0)可有可无)。

    但这样依然不太好操作,所以我们要进行进一步转化。

    转化

    考虑把操作序列转化为一个二进制数,(or)(0)(and)(1),且较后操作处于较高位。

    然后把题目中给出的(n)个长度为(m)的数变为(m)个长度为(n)的数,第(i)个数由初始的(n)个数的第(i)位组成,且编号较大的数处于较高位。

    这样一来操作与数就可以一一对应了。

    然后考虑如果对应位相等,表示该操作无影响。

    而不相等那一位,若操作序列中的值为(0),数中的值为(1),即操作序列中这一位小于该数中的这一位,说明是赋值为(1),反之是赋值为(0)

    由于二进制下比大小看不相等的最高位,所以我们可以得出结论:

    • 若操作序列所表示的二进制数小于该数,则最终结果中该数所对应位上为(1)(不能等于是因为一定要有(or 1)操作)。
    • 若操作序列所表示的二进制数大于等于该数,则最终结果中该数所对应位上为(0)

    也就是说,一个符合条件的操作序列所表示的二进制数,要满足其小于所有应得位为(1)的数,大于等于所有应得位为(0)的数。

    而这也就是要小于所有应得位为(1)的数的最小值,大于等于所有应得数为(0)的数的最大值。

    则可以先将所有数排序,然后求出所有数取模后的值,然后对于询问从小到大找最大值,从大到小找最小值即可。

    具体实现详见代码。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 1000
    #define M 5000
    #define X 1000000007
    #define Inc(x,y) ((x+=(y))>=X&&(x-=X))
    using namespace std;
    int n,m,v[M+5],pw[M+5];
    struct data
    {
    	int p;string s;
    	I bool operator < (Con data& o) Con {return s<o.s;}
    }s[M+5];
    I int XSub(CI x,CI y) {return x<y?x-y+X:x-y;}
    int main()
    {
    	RI Qt,i,j,l,r;string st;for(scanf("%d%d%d",&n,&m,&Qt),i=1;i<=m;++i) s[i].p=i;//初始化
    	for(i=1;i<=n;++i) for(cin>>st,j=1;j<=m;++j) s[j].s=st[j-1]+s[j].s;//初始化出字符串
    	for(pw[0]=i=1;i<=n;++i) (pw[i]=pw[i-1]<<1)>=X&&(pw[i]-=X);v[m+1]=pw[n];//预处理2的幂
    	for(sort(s+1,s+m+1),i=1;i<=m;++i) {for(j=0;j^n;++j) s[i].s[j]^48&&Inc(v[i],pw[n-j-1]);}//排序,预处理出每个数的值
    	W(Qt--)
    	{
    		for(cin>>st,l=0,i=m;i;--i) if(st[s[i].p-1]^'1') {l=i;break;}//找最小值
    		for(r=m+1,i=1;i<=m;++i) if(st[s[i].p-1]^'0') {r=i;break;}//找最大值
    		printf("%d
    ",l<=r?XSub(v[r],v[l]):0);//计算答案
    	}return 0;
    }
    
  • 相关阅读:
    [Github]在仓库中添加Sponsor赞助者按钮
    SpringMVC面试题常问的29道(附答案)
    Spring常问面试题及答案汇总(2020版)
    Java面试题及答案整理(2020最新版)
    MySQL数据库下载及安装教程(最新版!史上最详细!)
    +0与-0在plc传递数值上的坑
    halcon极坐标转换与亮暗缺陷检测结合的案例(转)
    互联网项目管理
    zabbix 监控IO DISK
    转 更改当前schema
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu4424.html
Copyright © 2020-2023  润新知