给定一个字符串集合 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
思路
要计算两个串的匹配价值,我们记录S集合中的串为模式串,T为匹配串。串的长度最大为12,两个串匹配之后得到的还是在0-12位的字符串,所以我们可以预先得到所有模式串和匹配串匹配之后得到的价值我们使用g数组记录两个串匹配后得到的串的价值。g[i]表示匹配后得到的字符串将其转换为其对应的十进制数--i,g[i]表示其价值(此匹配后的字符串中为1的位置加上其对应的价值w)。我们现在已经知道所有字符串匹配后的价值。此时我们使用h[i][y]数组记录与i(01字符串对应的十进制数)字符串匹配得到价值为y的字符串的个数。因为S字符串数组中会有重复输入的01字符串,所以我们使用f[]数组记录字符串个数。最后我们计算h[i][y]数组的前缀和。所以在最后的q次查询中,我们只需要查找前缀和数组即可。因为k<=100,所以我们在计算前缀和是只需要计算到h[i][100]
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=12; 4 const int M=5e5+10; 5 const int N1=5000; 6 int w[N]; 7 int g[N1];//存储i,j匹配后得到的字符串价值 8 int n,m,k,q; 9 string s[M]; 10 string T; 11 int f[N1]; 12 int h[N1][2000]; 13 int qw[20]={1}; 14 int main(){ 15 cin>>n>>m>>q; 16 for (int i=1;i<n;i++) qw[i]=qw[i-1]<<1; 17 for(int i=n-1;i>=0;i--){ 18 cin>>w[i]; 19 } 20 for(int i=0;i<m;i++){ 21 cin>>s[i]; 22 int x=0; 23 for(int j=0;j<n;j++){ 24 x+=(s[i][j]-'0')*qw[n-j-1]; 25 } 26 // cout<<s[i]<<" "<<x<<endl; 27 f[x]++; 28 } 29 for(int i=1;i<(1<<n);i++){ 30 int count=0; 31 int k1=i; 32 for (int j=0;j<n;j++) { 33 if(i&qw[j]) g[i]+=w[j]; 34 } 35 // printf("g[%d]=%d\n",i,g[i]); 36 } 37 for(int i=0;i<(1<<n);i++){ 38 for(int j=0;j<(1<<n);j++){ 39 int K1=(i^j)^((1<<n)-1); 40 // cout<<i<<" "<<j<<" "<<K1<<" "; 41 h[i][g[K1]]+=f[j]; 42 // printf("h[%d][%d]=%d\n",i,g[K1],h[i][g[K1]]); 43 } 44 } 46 for(int i=0;i<4096;i++){ 47 for(int j=1;j<=100;j++){ 48 h[i][j]+=h[i][j-1]; 49 } 50 } 51 while(q--){ 52 cin>>T>>k; 53 int y=0; 54 for(int i=0;i<n;i++){ 55 y+=(T[i]-'0')*qw[n-i-1]; 56 } 58 cout<<h[y][k]<<endl; 59 } 60 return 0; 61 }标签:周赛,匹配,nn,int,字符串,68,20,价值 From: https://www.cnblogs.com/penoy/p/16770192.html