寻宝游戏
Description
某大学每年都会有一次Mystery Hunt的活动,玩家需要根据设置的线索解谜,找到宝藏的位置,前一年获胜的队伍可以获得这一年出题的机会。
作为新生的你,对这个活动非常感兴趣。你每天都要从西向东经过教学楼一条很长的走廊,这条走廊是如此的长,以至于它被人戏称为infinite corridor。一次,你经过这条走廊时注意到在走廊的墙壁上隐藏着
很快,在最新的一期的Voo Doo杂志上,你发现了
聪明的你很快发现了这些数字的含义。
保持数组
你需要插入
然而,infinite corridor真的很长,这意味着数据范围可能非常大。因此,答案也可能非常大,但是你发现由于谜题的特殊性,你只需要求答案模1000000007的值。
Input
第一行三个数
接下来
接下来
Output
输出
Sample Input
5 3 0
1 2 3 4 5
3 5
5 0
1 4
Sample Output
5
7
6
7
HINT
考场上不会倒推做法,暴力还超时了,正解想到一半就想不动了(而且也不知道那是正解)……
咱是真的菜QAQ
思路:
首先很显然需要按位考虑。
观察每一位,可以发现,
若某一位的值为
考虑把所有运算符写成一个01串,令所有|运算为
同样考虑蒋所有数某一位的
可以发现,把最右端看成最高位,从高到低比较同为
于是可以发现,能使结果为
考虑对于每一位形成的01串排序。
对于每次询问,首先观察是否合法,即是否有合法的运算符集合对于询问串的每一位均满足要求。
即,对于询问串,所有为
然后计算答案,可以发现是小于最小的为
于是就做完了~
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1009;
const int M=5009;
const int md=1e9+7;
int n,m,q;
int rk[M],sum[M],tmp[M],pows[N];
char s[M];
int main()
{
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=m;i++)
rk[i]=i;
pows[0]=1;
for(int i=1;i<=n;i++)
pows[i]=pows[i-1]*2ll%md;
for(int i=1;i<=n;i++)
{
int cnt[]={0,0};
scanf("%s",s+1);
for(int j=1;j<=m;j++)
{
sum[j]=(sum[j]+(ll)(s[j]-'0')*pows[i-1])%md;
cnt[s[j]-'0']++;
}
cnt[1]+=cnt[0];
for(int j=m;j;j--)
tmp[cnt[s[rk[j]]-'0']--]=rk[j];
swap(rk,tmp);
}
reverse(rk+1,rk+m+1);
for(int i=1;i<=q;i++)
{
scanf("%s",s+1);
int lst1=0,fst0=m+1;
for(int j=m;j>=1 && lst1==0;j--)
if(s[rk[j]]-'0')
lst1=j;
for(int j=1;j<=m && fst0==m+1;j++)
if(!(s[rk[j]]-'0'))
fst0=j;
if(lst1>fst0)
{
puts("0");
continue;
}
int c0=lst1>=1?sum[rk[lst1]]:pows[n];
int c1=fst0<=m?sum[rk[fst0]]:0;
printf("%d\n",(c0-c1+md)%md);
}
return 0;
}