• P4424 [HNOI/AHOI2018]寻宝游戏 思维题


    题意:

    戳这里

    分析:

    • 暴力 (O(qn imes 2^m))

    • 正解:

      stO 考场上直接切掉这道题的巨佬们,蒟蒻瑟瑟发抖

      我们按照操作和数字的组合分清况来讨论:

      (1 & 0 o 0) (1|0 o 1) (1 & 1 o 1) (1|1 o 1)

      (0 & 0 o 0) (0|0 o 0) (0&1 o 0) (0|1 o 1)

      我们观察发现第二列和第三列有一些特殊性质:

      (|0)(&1) 的组合不会对原来的值产生任何影响 而 (|1) 相当于赋值为 (1)(& 0) 相当于赋值为 (0)


    关键的一步来了,我们对操作进行转化,因为操作只有 (& |) 两种,和 (0,1) 一样,那么我们考虑将操作也转化成 (0,1) 序列, 我们把 (|) 看做 (0) , $& $ 看成 (1)

    这样一来,我们就能通过操作的大小关系来判断出最后每一位的结果,我们按位 考虑,对于每一位从 (n)(1) 看成一个从高到低的二进制数字序列,从 (n)(1) 的操作看成从高到低的二进制操作序列,如果操作序列和数字序列某一位相同,那么没有任何影响,如果操作序列某一位小于数字序列,相当于赋值为 (1) ,如果操作序列某一位大于数字序列,相当于赋值为 (0) 由于后来的操作会覆盖开始的操作,所以高位的答案会覆盖低位的答案,这和二进制下的大小一样,高位操作优先,所以我们发现,当

    1. 操作序列小于数字序列,这一位为 (1) ( 不能是等于数字序列,是因为最开始这一位为 (0) ,必须要有 (|1) 操作)
    2. 操作序列大于等于数字序列,这一位为 (0)

    然后我们对于原序列每一位,建出数字序列,然后根据查询串的 (0,1) 关系,判断出操作序列的上界和下界,之间的每一种操作都可以取到

    代码:

    #include<bits/stdc++.h>
    #define pii pair<int,int>
    #define mk(x,y) make_pair(x,y)
    #define lc rt<<1
    #define rc rt<<1|1
    #define pb push_back
    #define fir first
    #define sec second
    #define inl inline
    #define reg register
    
    using namespace std;
    
    namespace zzc
    {
    	inline int read()
    	{
    		int x=0,f=1;char ch=getchar();
    		while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    		while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    		return x*f;
    	}
    	
    	const int maxn = 5005;
    	const int mod = 1e9+7;
    	int n,m,q;
    	string s[maxn],r;
    	int rk[maxn],seq[maxn];
    	char ch;
    	
    	bool cmp(int x,int y)
    	{
    		return s[x]<s[y];
    	}
    	
    	long long calc(string &a,string &b)
    	{
    		long long bas=1,res=0;
    		for(int i=n-1;i>=0;i--)
    		{
    			res=(res+bas*(a[i]+mod-b[i])%mod)%mod;
    			bas=bas*2%mod;
    		}
    		return res;
    	}
    	
    	void work()
    	{
    		n=read();m=read();q=read();
    		for(int i=1;i<=n;i++)
    		{
    			for(int j=1;j<=m;j++)
    			{
    				ch=getchar();
    				while(ch!='0'&&ch!='1') ch=getchar();
    				s[j]+=ch;
    			}
    		}
    		for(int i=1;i<=m;i++) reverse(s[i].begin(),s[i].end());
    		for(int i=1;i<=n;i++) s[0]+='0',s[m+1]+='1';
    		for(int i=1;i<=m+1;i++) seq[i]=i;
    		sort(seq+1,seq+m+1,cmp);
    		for(int i=1;i<=m+1;i++) rk[seq[i]]=i;
    		while(q--)
    		{
    			cin>>r;
    			int dwn=0,upn=m+1;
    			for(int i=1;i<=m;i++)
    			{
    				if(r[i-1]=='0') dwn=max(dwn,rk[i]);
    				else upn=min(upn,rk[i]);
    			}
    			if(dwn>upn) puts("0");
    			else printf("%lld
    ",(1ll*(upn==m+1)?1:0)+calc(s[seq[upn]],s[seq[dwn]]));
    		}
    	}
    
    }
    
    int main()
    {
    	zzc::work();
    	return 0;
    }
    
    
  • 相关阅读:
    C#:如何设置MDI窗体
    asp.net在类库中使用EF 6.0时的相关配置
    asp.net中使用jquery ajax保存富文本的问题
    Asp.net Api中使用OAuth2.0实现“客户端验证”
    NLog在asp.net中的使用
    元素的隐藏特性
    jQuery 使用笔记
    获取标签的所有选择器存放在一个数组
    自己绘制的flex布局思维导图
    js打印三角形
  • 原文地址:https://www.cnblogs.com/youth518/p/14282338.html
Copyright © 2020-2023  润新知