洛谷P4424 [HNOI/AHOI2018]寻宝游戏 题解

Posted 。✧* ꧁王者꧂✧*

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷P4424 [HNOI/AHOI2018]寻宝游戏 题解相关的知识,希望对你有一定的参考价值。

题面
不得不说,这真的是一道二进制好题!!!
思路转换得极其精妙,看得我不禁连连叫好!!!
一般看到类似的与二进制运算符有关的题目,按位进行肯定是首要考虑的。
我们考虑在按位进行二进制运算时的性质:

从上图可以看出,当运算符是 ∣ | 且下一位数字是 1 1 1时,结果一定是 1 1 1;当运算符是&且下一位是 0 0 0时,结果一定是 0 0 0

从上图可以看出,当运算符是 ∣ | 且下一位是 0 0 0时,值不发生改变;当运算符是&且下一位是 1 1 1时,值不发生改变。
那么,试想,如果我们用 0 0 0 1 1 1分别表示 ∣ | 和&,那么,一个操作序列 o p op op,就可以用二进制表示了。这有什么用呢?
把对应的 o p op op序列与上图的性质进行对比,你会发现,当 o p op op的数与进行操作的数相同时,对结果不造成影响;不同时,会被操作的数覆盖原先值。比如: 00 对 应 ∣ 0 00对应|0 000 10 对 应 10对应 10& 0 0 0
接下来,我们考虑当多个 0 0 0 1 1 1进行二进制运算时,结果为 1 1 1和结果为 0 0 0时,对应的操作序列的特征。
显然, o p op op序列与 01 01 01序列对应位置相同时,当前位置不对结果造成影响,所以,我们只用考虑 01 01 01 10 10 10就行了,前者将值覆盖为1,后者将值覆盖为0,为使结果为1,我们要保证最后一个 01 01 01后不出现 10 10 10,也就是说,最后一个 01 01 01后的每一位都相同。这样的话,将 o p op op序列和 01 01 01序列翻转过来,那么 01 01 01序列对应的二进制数大于 o p op op序列。
同理,你会发现,当结果为0时, 01 01 01序列的二进制数小于等于 o p op op序列的二进制数。
于是,这道题就变成了比大小。每给出一个 a n s ans ans,根据每一个位置上是 0 0 0还是 1 1 1,求出最终的答案区间。
为了保证时间复杂度,我们要先对 m m m个长度为 n n n的二进制序列从小到大排序。这在输入的同时就可以操作。
代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 5e3 + 10 , p = 1e9 + 7;
int n , m , Q , ra[N] , la[N] , a[N] , ans[N] , b[N][1001];
char s[N];
int main()
{
	cin >> n >> m >> Q;
	for(int i = 1;i <= m; i++)
	ra[i] = i;
	for(int i = 1; i <= n; i++)
	{
		scanf("%s" , s + 1);
		for(int j = 1; j <= m; j++)
		{
			a[j] = s[j] - '0';
			b[j][i] = a[j];
		}
		int cnt = 0;
		for(int j = 1; j <= m; j++)
		if(a[ra[j]] == 0) la[++cnt] = ra[j];
		for(int j = 1; j <= m; j++)
		if(a[ra[j]] == 1) la[++cnt] = ra[j];
		for(int j = 1; j <= m; j++)
		ra[j] = la[j];
	}
	for(int i = 1; i <= m ; i++)
	{
		for(int j = n; j >= 1; j--)
		{
			ans[i] = (2ll * ans[i] + b[i][j]) % p;
		}
	}
	for(int i = 1; i <= n; i++)
	ans[m+1] = (2ll * ans[m+1] + 1) % p;
	ra[m+1] = m + 1;
	ans[m+1] += 1;
	while(Q--)
	{
		scanf("%s" , s + 1);
		int L = 0 , R = m + 1;
		for(int i = 1 ; i <= m; i++)
		if(s[ra[i]]=='1')
		{
			R = i;
			break;
		}
		for(int i = m; i >= 1; i--)
		{
			if(s[ra[i]]=='0')
			{
				L = i;
				break;
			}
		}
		printf("%d\\n",R < L? 0 : (ans[ra[R]] - ans[ra[L]] + p) % p);
	}
	return 0;
}

以上是关于洛谷P4424 [HNOI/AHOI2018]寻宝游戏 题解的主要内容,如果未能解决你的问题,请参考以下文章

[HNOI/AHOI2018]转盘

[HNOI/AHOI2018]转盘

HNOI(AHOI)2018游记

题解 [HNOI/AHOI2018]道路 (动态规划)

#10 //I [HNOI/AHOI2018]毒瘤

洛谷 P2910 [USACO08OPEN]寻宝之路Clear And Present Danger