给定一个字符串集合 SS,SS 中包含 mm 个长度为 nn 的 0101 字符串,集合中可能包含重复元素。
给定一个长度为 nn 的整数序列 w1,w2,…,wnw1,w2,…,wn。
关于两个长度为 nn 的 0101 字符串 s,ts,t 的匹配价值 VV,其具体计算方法如下:
- 设字符串 ss 的各位字符从左到右依次为 s1,s2,…,sns1,s2,…,sn。
- 设字符串 tt 的各位字符从左到右依次为 t1,t2,…,tnt1,t2,…,tn。
- 初始时,V=0V=0。
- 对于所有 ii(1≤i≤n)(1≤i≤n),如果 si=tisi=ti,则 VV 加上 wiwi。
- 最终得到的 VV 即为两字符串的匹配价值。
现在,给定 qq 个询问,每个询问包含一个长度为 nn 的 0101 字符串 tt 以及一个整数 kk,具体询问内容为:请你计算并输出集合 SS 中有多少个元素满足,与给定字符串 tt 的匹配价值不大于 kk。
注意,如果集合中多个相同的元素均满足询问条件,则每个元素均应被计数。
输入格式
第一行包含三个整数 n,m,qn,m,q。
第二行包含 nn 个整数 w1,w2,…,wnw1,w2,…,wn。
接下来 mm 行,每行包含一个长度为 nn 的 0101 字符串,表示集合 SS 中的一个元素。
最后 qq 行,每行包含一个长度为 nn 的 0101 字符串 tt 和一个整数 kk,表示一个询问。
输出格式
每个询问输出一行答案,一个整数,表示满足询问条件的元素个数。
数据范围
前 33 个测试点满足 1≤m,q≤51≤m,q≤5。
所有测试点满足 1≤n≤121≤n≤12,1≤m,q≤5×1051≤m,q≤5×105,0≤wi≤1000≤wi≤100,0≤k≤1000≤k≤100。
输入样例1:
2 4 5
40 20
01
01
10
11
00 20
00 40
11 20
11 40
11 60
输出样例1:
2
4
2
3
4
输入样例2:
1 2 4
100
0
1
0 0
0 100
1 0
1 100
输出样例2:
1
2
1
2
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1<<12,M=110;
int n,m,q;
int w[12],weight[N];
int cnt[N],ans[N][N];
int get(char str[]) {
reverse(str,str+n);
int res=0;
for(int i=0; i<n; i++) {
res=res*2+str[i]-'0';
}
return res;
}
int main() {
scanf("%d%d%d",&n,&m,&q);
for(int i=0; i<n; i++) {
scanf("%d",&w[i]);
}
for(int i=0; i<1<<n; i++) {
for(int j=0; j<n; j++) {
if(i>>j&1)//如果i的第j位是1
weight[i]+=w[j];
}
}
char str[20];
while(m--) {
scanf("%s",str);
cnt[get(str)]++;
}
int all=(1<<n)-1;//方便待会相同为取1,不同位取0
for(int i=0; i<1<<n; i++) {
for(int j=0; j<1<<n; j++) {
int t=weight[i^j^all];
//得到i查询串与j匹配串相同位置取
//1后的值,我们的weight记录的就是当前值的权值
if(t<=100) {
ans[i][t]+=cnt[j];
//查询i串,在权值t的情况下,有多少串符合这个匹配值
}
}
}
for(int i=0; i<1<<n; i++) {
for(int j=1; j<=100; j++) {
ans[i][j]+=ans[i][j-1];//求出前缀和
}
}
while(q--) {
int k;
scanf("%s%d",str,&k);
cout<<ans[get(str)][k]<<endl;
}
return 0;
}