P4424 [HNOI/AHOI2018]寻宝游戏


某大学每年都会有一次Mystery Hunt的活动,玩家需要根据设置的线索解谜,找到宝藏的位置,前一年获胜的队伍可以获得这一年出题的机会。

作为新生的你,对这个活动非常感兴趣。你每天都要从西向东经过教学楼一条很长的走廊,这条走廊是如此的长,以至于它被人戏称为infinite corridor。一次,你经过这条走廊时注意到在走廊的墙壁上隐藏着nn 个等长的二进制的数字,长度均为mm 。你从西向东将这些数字记录了下来,形成一个含有nn 个数的二进制数组a_1,a_2,...,a_na1​,a2​,...,an​ 。

很快,在最新的一期的Voo Doo杂志上,你发现了qq 个长度也为mm 的二进制数r_1,r_2,...,r_qr1​,r2​,...,rq​ 。

聪明的你很快发现了这些数字的含义。

保持数组a_1,a_2,...,a_na1​,a2​,...,an​ 的元素顺序不变,你可以在它们之间插入∧∧ (按位与运算)或者∨∨ (按位或运算)。例如:11011∧00111=0001111011∧00111=00011 ,11011∨00111=1111111011∨00111=11111 。

你需要插入nn 个运算符,相邻两个数之前恰好一个,在第一个数的左边还有一个。如果我们在第一个运算符的左边补入一个0,这就形成了一个运算式,我们可以计算它的值。与往常一样,运算顺序是从左到右。有趣的是,出题人已经告诉你这个值的可能的集合——Voo Doo杂志里的那些二进制数r_1,r_2,...,r_qr1​,r2​,...,rq​ ,而解谜的方法,就是对r_1,r_2,...,r_qr1​,r2​,...,rq​ 中的每一个值r_iri​ ,分别计算出有多少种方法填入这nn 个计算符,使的这个运算式的值是r_iri​ 。

然而,infinite corridor真的很长,这意味着数据范围可能非常大。因此,答案也可能非常大,但是你发现由于谜题的特殊性,你只需要求答案模1000000007的值。

输入输出格式


输入格式:

第一行三个数nn ,mm ,qq ,含义如题所述。

接下来nn 行,其中第ii 行有一个长度为mm 的二进制数,左边是最高位,表示a_iai​ 。

接下来qq 行,其中第ii 行有一个长度为mm 的二进制数,左边是最高位,表示r_iri​ 。

输出格式:

输出qq 行,每行一个数,其中的ii 行表示对于r_iri​ 的答案。

输入输出样例


输入样例#1:


输出样例#1:


输入样例#2: 


输出样例#2: 


说明


对于 10% 的数据,n \le 20, m \le 30, q = 1n≤20,m≤30,q=1

对于另外 20 的数据,n \le 1000, m \le 16n≤1000,m≤16

对于另外 40 的数据,n \le 500, m \le 1000n≤500,m≤1000

对于全部的数据1≤n≤1000,1≤m≤5000,1≤q≤10001≤n≤1000,1≤m≤5000,1≤q≤1000

分析:


倒着来推,每次枚举每个位置是or 还是 and。设每个串为S[i],设每次查询的串为G

然后有个表 :(设当前枚举到第i个字符串的第j位,设F[i][j]表示(1 ~ i - 1)操作后第j位为0/1)

————————————

解释起来也很简单:

比如说在枚举最后一个操作时,我们查询字符串第j位为0,第n个字符串第j位为1,如果选了or操作,无论[1,n - 1]的操作怎么枚举,在 or 1过后,值都只会等于1,不合法,记F[i][j] == -1

比如说在枚举最后一个操作时,我们查询字符串第j位为1,第n个字符串第j位为1,如果选了or操作,无论[1,n - 1]的操作怎么枚举,在 or 1过后,值都会等于1,一定和合法,记F[i][j] == 0/1

比如说在枚举最后一个操作时,我们查询字符串第j位为1,第n个字符串第j位为1,如果选了ang操作,只有当[1,n - 1]的操作枚举使第j位为1时,才有1 & 1 == 1,记F[i][j] == 1

以此类推,推下来发现每次推的F[i][j]除了0/1和-1的状态,其他位都是和原字符串一样的,这样就不用记录F[i][j],只用记录有哪些位置满足了 0 / 1,记为 t。

Bfs按层枚举深搜树,然后记录每层有哪些合法的 t 状态,按层推下去。复杂度是O(2^n * q *(位运算代价) )

恭喜你,得到10分了

剪枝


-1表示(1~i - 1)的操作怎么枚举都不可能满足。

0/1表示(1 ~ i - 1)的操作随便枚举都可以满足。

这样我们倒着2^n次方枚举所有填的可能,当出现-1就剪枝,当全部位都为0/1就可以直接加上2^(i - 1),并剪枝。

这样剪下来,每一层状态数最多为2,是不是很神奇。。

然后复杂度就变成了O(nq * (位运算代价))。

使用bitset(要手写),把位运算代价优化成5000 / 64 = 78

总复杂度O(78nq)

AC代码:


# include <iostream>
# include <cstdio>
# include <cstring>
using namespace std;
typedef unsigned long long llu;
const int N = ;
const int mod = 1e9 + ;
int block,n,m,Q;
struct bitset{
llu p[];
void read()
{
memset(p,0llu,sizeof p);
char i = getchar();
while(!isdigit(i))i = getchar();
for(int j = ;j < m;j++,i = getchar())p[j / ] |= (((llu)(i - '')) << (j % ));
}
void clear(){for(int i = ;i <= block;i++)p[i] = ;}
}s[N],f[N],nt,t1,t2,v1,v2,g,c1,c2,que[][];
int ret,dt,cur,tot;
llu ans,bac[N];
void init()
{
block = (m - ) / ;
bac[] = ;for(int i = ;i <= n;i++)bac[i] = (bac[i - ] << ) % mod;
memset(nt.p,0llu,sizeof nt.p);
for(int j = ;j < m;j++)nt.p[j / ] |= (1llu << (j % ));
for(int i = ;i <= n;i++)
{
s[i].read();
for(int j = ;j <= block;j++)
f[i].p[j] = s[i].p[j] ^ nt.p[j];
}
}
int main()
{
scanf("%d %d %d",&n,&m,&Q);
init();
while(Q--)
{
g.read();dt = ans = cur = ;que[cur][++dt].clear();
for(int i = n;i;i--)
{
tot = dt;cur ^= ;dt = ;
for(int j = ;j <= tot;j++)
{
bool f1 = true,f2 = true,l1 = true,l2 = true;
for(int k = ;k <= block;k++)
{
if(!f1 && !f2)break;
if(que[cur ^ ][j].p[k] == nt.p[k])
{
if(f1)t1.p[k] = nt.p[k];
if(f2)t2.p[k] = nt.p[k];
continue;
}
if(f1)v1.p[k] = s[i].p[k] & (s[i].p[k] ^ g.p[k]);
if(f2)v2.p[k] = g.p[k] & (s[i].p[k] ^ g.p[k]);
if(f1 && (v1.p[k] & que[cur ^ ][j].p[k]) != v1.p[k])f1 = false;
if(f2 && (v2.p[k] & que[cur ^ ][j].p[k]) != v2.p[k])f2 = false;
if(f1)t1.p[k] = que[cur ^ ][j].p[k] | (s[i].p[k] ^ v1.p[k]);
if(f2)t2.p[k] = que[cur ^ ][j].p[k] | (f[i].p[k] ^ v2.p[k]);
if(f1 && t1.p[k] != nt.p[k])l1 = false;
if(f2 && t2.p[k] != nt.p[k])l2 = false;
}
if(f1)
{
if(l1)ans = (ans + bac[i - ]) % mod;
else que[cur][++dt] = t1;
}
if(f2)
{
if(l2)ans = (ans + bac[i - ]) % mod;
else que[cur][++dt] = t2;
}
}
}
for(int j = ;j <= dt;j++)
{
bool f1 = true;
for(int k = ;k <= block;k++)
{
if((que[cur][j].p[k] ^ nt.p[k]) & g.p[k]){f1 = false;break;}
}
ans += f1;
}
cout<<ans<<endl;
}
}

[Bzoj5285][洛谷P4424][HNOI/AHOI2018]寻宝游戏(bitset)的更多相关文章

  1. 洛谷P4424 [HNOI/AHOI2018]寻宝游戏(思维题)

    题意 题目链接 Sol 神仙题Orz Orz zbq爆搜70.. 考虑"与"和"或"的性质 \(0 \& 0 = 0, 1 \& 0 = 0\) ...

  2. BZOJ5285 & 洛谷4424 & UOJ384:[HNOI/AHOI2018]寻宝游戏——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=5285 https://www.luogu.org/problemnew/show/P4424 ht ...

  3. [洛谷P4436] HNOI/AHOI2018 游戏

    问题描述 一次小G和小H在玩寻宝游戏,有n个房间排成一列,编号为1,2,...,n,相邻的房间之间都有一道门.其中一部分门上锁(因此需要有对应的钥匙才能开门),其余的门都能直接打开.现在小G告诉了小H ...

  4. 【洛谷4424】[HNOI_AHOI2018]寻宝游戏(我也不知道括号里该写啥)

    题目 洛谷 4424 分析 感觉思路比较神仙. 对于按位与和按位或两种运算,显然每一位是独立的,可以分开考虑. 对于某一位,「与 \(0\)」会将这一位变成 \(0\),「或 \(1\)」会将这一位变 ...

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

    点此看题面 大致题意: 给你\(n\)个\(m\)位二进制数.每组询问给你一个\(m\)位二进制数,要求你从\(0\)开始,依次对于这\(n\)个数进行\(and\)或\(or\)操作,问有多少种方案 ...

  6. 洛谷P4438 [HNOI/AHOI2018]道路(dp)

    题意 题目链接 Sol 每当出题人想起他出的HNOI 2018 Day2T3,他都会激动的拍打着轮椅 读题比做题用时长系列... \(f[i][a][b]\)表示从根到\(i\)的路径上,有\(a\) ...

  7. 洛谷P4425 [HNOI/AHOI2018]转盘(线段树)

    题意 题目链接 Sol 首先猜一个结论:对于每次询问,枚举一个起点然后不断等到某个点出现时才走到下一个点一定是最优的. 证明不会,考场上拍了3w组没错应该就是对的吧... 首先把数组倍长一下方便枚举起 ...

  8. [HNOI/AHOI2018]寻宝游戏

    题目大意: $n(n\le1000)$个$m(m\le5000)$位的二进制数,第$0$个数为$0$.用$\wedge$和$\vee$将这些数连接起来.$q(q\le1000)$次询问,每次给定一个$ ...

  9. 洛谷 P4437 [HNOI/AHOI2018]排列(贪心+堆,思维题)

    题面传送门 开始 WA ycx 的遗产(bushi 首先可以将题目转化为图论模型:\(\forall i\) 连边 \(a_i\to i\),然后求图的一个拓扑序 \(b_1,b_2,\dots b_ ...

随机推荐

  1. HDU 3957 Street Fighter (最小支配集 DLX 重复覆盖+精确覆盖 )

    DLX经典题型,被虐惨了…… 建一个2*N行3*N列的矩阵,行代表选择,列代表约束.前2*N列代表每个人的哪种状态,后N列保证每个人至多选一次. 显然对手可以被战胜多次(重复覆盖),每个角色至多选择一 ...

  2. mysql5.6版本修改密码

     UPDATE user SET Password=PASSWORD('新密码') WHERE User='root'; 

  3. 在.net2.0中实现Action和Func方法

    由于这两个是在.net3.5中新加入的特性,所以我们需要自己写一下. 格式如下: delegate void Action();        delegate void Action<T, T ...

  4. HDU - 3072 Intelligence System

    题意: 给出一个N个节点的有向图.图中任意两点进行通信的代价为路径上的边权和.如果两个点能互相到达那么代价为0.问从点0开始向其余所有点通信的最小代价和.保证能向所有点通信. 题解: 求出所有的强连通 ...

  5. 51NOD 1554 欧姆诺姆和项链 巧妙利用KMP

    请戳这里! #include<cstdio> #define N 1000100 char s[N]; int n,k,nxt[N],ans[N]; int main() { scanf( ...

  6. POJ 2186 受欢迎的牛 Tarjan基础题

    #include<cstdio> #include<algorithm> #include<cstring> #include<vector> #inc ...

  7. 雅礼集训 Day1 T2 折射

    折射 题目描述 小\(\mathrm{Y}\)十分喜爱光学相关的问题,一天他正在研究折射. 他在平面上放置了\(n\)个折射装置,希望利用这些装置画出美丽的折线. 折线将从某个装置出发,并且在经过一处 ...

  8. box-pack

    box-pack表示父容器里面子容器的水平对齐方式,可选参数如下所示: start | end | center | justify <article class="wrap" ...

  9. CSS清除浮动常用方法小结 CSS clear both {overflow:auto;zoom:1;}

    常用的清除浮动的方法有以下三种: 此为未清除浮动源代码,运行代码无法查看到父级元素浅黄色背景 <!DOCTYPE html><html><head> <met ...

  10. clips apache配置虚拟主机

    >>单个虚拟主机 一个一个的配置 1.httpd.conf文件里 Include conf/extra/httpd-vhosts.conf //取消#注释 2.httpd-vhosts.c ...