注意在这题中01串都很短,长度不超过12,可以使用集合转换为整数表示,然后开一个二维数组,预处理一下所有可能查询的串和最大Wu值存在里面就可以了。
准确地说,数组第一维保存可能给定的一个01串转换为整数的值 $i$,第二位则是当Wu值 恰好等于 $v$ 时的答案,随后在线地处理每一个询问,将小于最大Wu值的所有答案加起来即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
|
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;
namespace CF1017D { class Program 大专栏 【题解】CF1017D { public class Global{ public static int[,] arr; public static int[] cnt, wuVal; }
static void Main(string[] args) { string inp;string[] div;
int len, totTemp, totQuery, maxWu, x, _count;
inp = Console.ReadLine();div = inp.Split(' '); len = Convert.ToInt32(div[0]);totTemp = Convert.ToInt32(div[1]);totQuery = Convert.ToInt32(div[2]);
Global.arr = new int[(1 << 13), 101]; Global.cnt = new int[1 << 13]; Global.wuVal = new int[len];
//read inp = Console.ReadLine(); div = inp.Split(' '); for(int i = 0; i < len; i++) Global.wuVal[i] = Convert.ToInt32(div[i]); for(int i = 0; i < totTemp; i++) { inp = Console.ReadLine(); x = 0; for(int j = 0; j < len; j++) if(inp[j] == '1') x |= (1 << j); Global.cnt[x]++; }
//预处理 for(int i = 0; i < (1 << len); i++) for(int j = 0; j < (1 << len); j++) if(Global.cnt[i] > 0) { x = 0; //代价 for(int k = 0; k < len; k++) if((i & (1 << k)) == (j & (1 << k))) x += Global.wuVal[k]; if(x <= 100) Global.arr[j, x] += Global.cnt[i]; }
while(totQuery-- > 0) { inp = Console.ReadLine();div = inp.Split(' '); maxWu = Convert.ToInt32(div[1]);
_count = x = 0; for(int i = 0; i < len; i++) if(inp[i] == '1') x |= (1 << i);
for(int i = 0; i <= maxWu; i++) _count += Global.arr[x, i]; Console.WriteLine(_count.ToString()); }
} } }
|
代码就是这样了,这道题时间卡得非常紧,导致我用C#调了半天还是超时。逐行翻译成 C++ 代码之后就AC了.