【NOIP2016练习】T3 subset (分块,状压DP)

3 subset

3.1 题目  

一开始你有一个空集,集合可以出现重复元素,然后有个操作

  1. add s

在集合中加入数字 s。

  1. del s

在集合中删除数字 s。保证存在

  1. cnt s

查询满足 a&s = a 条件的 a 的个数

3.2 输入

第一行一个整数接下来行,每一行都是个操作中的一个

3.3 输出

对于每个 cnt 操作输出答案

3.4 Sample Input

7

add 11 cnt 15 add 4 add 0 cnt 6 del 4 cnt 15

3.5 Sample Output

1

2

2

3.6 数据

对于 30% 的数据满足:1 n 1000

对于 100% 的数据满足,1 n 200000 , 0 < s < 216

思路:

分块计算。a[pre][suf],其中 pre < 28,suf < 28,表示前面位是 pre,后面位是 suf 

子集的数字的个数。

那么对于每个 add  del 操作都可以最多 28 时间枚举 suf 更新数组。对于 cnt 操作,最多 28 枚举 pre,计算答案即可时间复杂度 O(n 28)

 1 var dp:array[0..300,0..300]of longint;
 2     s1,s2,n,i,x,j:longint;
 3     ch:string;
 4 
 5 procedure dfs1(var s1,s2:longint;k,s:longint);
 6 begin
 7  if k>7 then
 8  begin
 9   inc(dp[s1,s]);
10   exit;
11  end;
12  if s2 and (1<<k)>0 then dfs1(s1,s2,k+1,s+(1<<k))
13   else
14   begin
15    dfs1(s1,s2,k+1,s);
16    dfs1(s1,s2,k+1,s+(1<<k));
17   end;
18 end;
19 
20 procedure dfs2(var s1,s2:longint;k,s:longint);
21 begin
22  if k>7 then
23  begin
24   dec(dp[s1,s]);
25   exit;
26  end;
27  if s2 and (1<<k)>0 then dfs2(s1,s2,k+1,s+(1<<k))
28   else
29   begin
30    dfs2(s1,s2,k+1,s);
31    dfs2(s1,s2,k+1,s+(1<<k));
32   end;
33 end;
34 
35 procedure add(x:longint);
36 var i:longint;
37 begin
38  s1:=0; s2:=0;
39  for i:=15 downto 8 do
40   if x and (1<<i)>0 then s1:=s1+1<<(i-8);
41   for i:=7 downto 0 do
42    if x and (1<<i)>0 then s2:=s2+1<<i;
43  dfs1(s1,s2,0,0);
44 end;
45 
46 procedure del(x:longint);
47 var i:longint;
48 begin
49  s1:=0; s2:=0;
50  for i:=15 downto 8 do
51   if x and (1<<i)>0 then s1:=s1+1<<(i-8);
52   for i:=7 downto 0 do
53    if x and (1<<i)>0 then s2:=s2+1<<i;
54  dfs2(s1,s2,0,0);
55 end;
56 
57 function cnt(x:longint):longint;
58 var ret,i,s:longint;
59 begin
60  ret:=0;
61  s1:=0; s2:=0;
62  for i:=15 downto 8 do
63   if x and (1<<i)>0 then s1:=s1+1<<(i-8);
64  for i:=7 downto 0 do
65   if x and (1<<i)>0 then s2:=s2+1<<i;
66  s:=s1;
67  while s>0 do
68  begin
69   ret:=ret+dp[s,s2];
70   s:=s1 and (s-1);
71  end;
72  ret:=ret+dp[0,s2];
73  exit(ret);
74 end;
75 
76 begin
77  assign(input,'subset.in'); reset(input);
78  assign(output,'subset.out'); rewrite(output);
79  readln(n);
80  for i:=1 to n do
81  begin
82   readln(ch);
83   x:=0;
84   for j:=5 to length(ch) do x:=x*10+ord(ch[j])-ord('0');
85   if ch[1]='a' then add(x);
86   if ch[1]='d' then del(x);
87   if ch[1]='c' then writeln(cnt(x));
88  end;
89  close(input);
90  close(output);
91 end.
原文地址:https://www.cnblogs.com/myx12345/p/6060588.html