jzoj. 3889. 【NOIP2014模拟10.25B组】序列问题

Description

小H是个善于思考的学生,她正在思考一个有关序列的问题。
她的面前浮现出了一个长度为n的序列{ai},她想找出两个非空的集合S、T。
这两个集合要满足以下的条件:
两个集合中的元素都为整数,且都在 [1, n] 里,即Si,Ti ∈ [1, n]。
对于集合S中任意一个元素x,集合T中任意一个元素y,满足x < y。
对于大小分别为p, q的集合S与T,满足 a[s1] xor a[s2] xor a[s3] … xor a[sp] = a[t1] and a[t2] and a[t3] … and a[tq].
小H想知道一共有多少对这样的集合(S,T),你能帮助她吗?

Input

第一行,一个整数n
第二行,n个整数,代表ai。

Output

仅一行,表示最后的答案。

Sample Input

4
1 2 3 3

Sample Output

4
【样例解释】
S = {1,2}, T = {3}, 1 ^ 2 = 3 = 3 (^为异或)
S = {1,2}, T = {4}, 1 ^ 2 = 3 = 3
S = {1,2}, T = {3,4} 1 ^ 2 = 3 & 3 = 3 (&为与运算)
S = {3}, T = {4} 3 = 3 = 3

Data Constraint

30%: 1 <= n <= 10
60%: 1 <= n <= 100
100%: 1 <= n <= 1000, 0 <= ai < 1024

分析:
30%:枚举每个数所在的集合或者不选,然后判定即可。复杂度 O(n*3^n)。
60%: Dp,两个数相等就相当于两个数的 xor 为 0。设 f[i][j][k=0..2]代表 处理到第 I 个数,
如果 k = 1 代表 and 值为 j,如果 k = 2 代表 xor 值为 j,如果 k = 0 则代表一个元素都没
取。所以很容易得到方程:
f[i][j][0] = f[i + 1][j][0]
f[i][j & ai][1] = f[i + 1][j][1] + f[i + 1][j][0] + f[i + 1][j & ai][1]
f[i][j ^ ai][2] = f[i + 1][j][1] + f[i + 1][j][2] + f[i + 1][j ^ ai][2];
最后 f[1][0][2]就是答案, 复杂度为 O(n * 1024 * 3)
DP 还可以分开用 f[i][j]和 g[i][j]表示前 i 个 xor 值为 j,后 i 个 and 值为 j 的方案数,
随后枚举分界点 k 来求总方案数。复杂度 O(n * 1024 * 3)。
100%:满分数据需要高精,答案位数较大,需要进行压位来防止 TLE,因为不知道答案的
位数究竟多大,压位后高精数组仍需要开的较大一些,所以原 DP 的数组滚动即可。

代码:

const
    mo=100000000;
type
    arr=array[0..40] of longint;
var
    n,i,j,p,q:longint;
    st:string;
    a:array[1..1000] of longint;
    f:array[0..1,0..1023,1..2,0..40] of longint;

function max(x,y:longint):longint;
begin
    if x>y then exit(x) else exit(y);
end;

procedure plus(var x:arr;y:arr);
var
    i:longint;
begin
    for i:=1 to max(x[0],y[0]) do begin
        x[i]:=x[i]+y[i];
        x[i+1]:=x[i+1]+x[i] div mo;
        x[i]:=x[i] mod mo;
    end;
    x[0]:=max(x[0],y[0]);
    if x[x[0]+1]>0 then inc(x[0]);
end;

begin

    readln(n);
    for i:=1 to n do read(a[i]);
    for i:=n downto 1 do begin
        p:=i mod 2; q:=(i+1) mod 2;
        f[p][a[i]][1][0]:=1;
        f[p][a[i]][1][1]:=1;
        for j:=0 to 1023 do begin
            plus(f[p][j][1],f[q][j][1]);
            plus(f[p][j and a[i]][1],f[q][j][1]);
            plus(f[p][j][2],f[q][j][2]);
            plus(f[p][j xor a[i]][2],f[q][j][2]);
            plus(f[p][j xor a[i]][2],f[q][j][1]);
        end;
        fillchar(f[q],sizeof(f[q]),0);
    end;

    for i:=f[1][0][2][0] downto 1 do begin
        str(f[1][0][2][i],st);
        if i<>f[1][0][2][0] then for j:=1 to 8-length(st) do st:='0'+st;
        write(st);
    end;
    if f[1][0][2][0]=0 then writeln(0);

end.

你可能感兴趣的:(DP)