jzoj4616. 【NOI2016模拟7.12】二进制的世界

Description

在这里插入图片描述

Input

在这里插入图片描述

Output

在这里插入图片描述

Sample Input

5 and 1
3 5 2 7 1

Sample Output

1 1
2 1
5 1
1 3

Data Constraint

在这里插入图片描述

题解

据说这是到NOI级别的题目?
怎么数据水到可以让O(216n)O(2^{16}*n)过掉?
虽说出题人被强烈谴责,但是我依然在比赛时利用水法水到了60分的好成绩。
烂透了。
20%
直接暴力即可。
40%
我们考虑到opt是xor操作,处理xor最大值的方式最好就是用trie这个强力的算法。
直接暴力建trie树,长度不大,也就16。
60%
此60%乃type=0的情况。
我们发现不需要考虑方案数。
继续利用trie做,离线建trie,维护每个数字最早出现时间。
如果是and操作,考虑把1子树合并到0子树上去。询问操作也是贪心。
or操作同理。
当然,我没打过。
70%~80%
在60%的基础上,考虑那个神奇的and操作。
我们发现,对于第i个数,and操作是只和a[i]中1的位置有关。
我们考虑新建一个数组f[s]f_{[s]}表示状态为s的方案有多少种。
利用dfs直接暴力构造a[i]的情况然后拿去与f匹配即可。
100%
由于上面的情况只考虑了and,那么像上面的思路一样考虑or说不定就过了呢?
然鹅出题人丧心病狂地出了一大堆655365,怎么办?
真·100%
我们发现,由于二进制长度为16。
而这个16又很难搞什么dp之类的。
有一个套路——把它分成一半!
设DP方程f[i,j]f_{[i,j]}表示前8位状态为i,在之前出现过的所有情况与后八位j&或|的后八位的最大值。
再记录一个g[i,j]g_{[i,j]}来记录方案数即可。
求答案?
设i之前某个数可以分成:a28+ba*2^8+b第i个数可以分成:c28+dc*2^8+d
每次枚举之前的一个数的a
那么答案即为:(a&c)28+f[a,d](a&c)*2^8+f_{[a,d]}(or是一样的)
转移?
把当前的c28+dc*2^8+d加入答案。
我们每次枚举之前出现过的b
那么转移即为f[c,b]=max(d&b)f_{[c,b]}=max(d&b)(or是一样的)
秒啊♂
注意!我们在区分and和or的时候,不要用字符串的判断,及其的慢。

标程

var
        i,j,k,l,n,m,kind,x,y,tot,p,q,zd:longint;
        a:array[1..100000] of longint;
        tree:array[0..1000000,0..1] of longint;
        bzz,gs:array[0..1000000] of longint;
        f,g:array[0..256,0..256] of longint;
        op:array[0..65536] of longint;
        jl:array[1..16] of longint;
        mi:array[0..16] of longint;
        s,t:ansistring;
        bz:boolean;
procedure insert(x,y:longint);
var
        j,k:longint;
begin
        if y>16 then
        begin
                inc(gs[x]);
                bzz[x]:=a[i];
                exit;
        end;
        if tree[x,jl[y]]=0 then
        begin
                inc(tot);
                tree[x,jl[y]]:=tot;
                insert(tot,y+1);
        end
        else
        begin
                insert(tree[x,jl[y]],y+1);
        end;
end;
procedure dg(x,y:longint);
begin
        if x>16 then
        begin
                inc(op[y]);
        end
        else
        begin
                if jl[x]=1 then
                begin
                        dg(x+1,y*2+1);
                        dg(x+1,y*2);
                end
                else
                begin
                        dg(x+1,y*2);
                end;
        end;
end;
procedure find(x,y:longint);
begin
        if x>16 then
        begin
                if op[y]>0 then
                begin
                        if kind=1 then writeln(y,' ',op[y])
                        else writeln(y);
                        bz:=true;
                end;
                exit;
        end
        else
        begin
                if jl[x]=1 then
                begin
                        if not bz then
                        find(x+1,y*2+1);
                        if not bz then
                        find(x+1,y*2);
                end
                else
                begin
                        find(x+1,y*2);
                end;
        end;
end;
begin
        assign(input,'binary.in');reset(input);
        assign(output,'binary.out');rewrite(output);
        mi[0]:=1;
        for i:=1 to 16 do
        begin
                mi[i]:=mi[i-1]*2;
        end;
        readln(s);
        bz:=true;
        t:='';
        for i:=1 to length(s) do
        begin
                if s[i]=' 'then
                begin
                        bz:=false;
                end
                else
                if (s[i]>='0') and (s[i]<='9') then
                begin
                        if bz then n:=n*10+ord(s[i])-48
                        else kind:=kind*10+ord(s[i])-48;
                end
                else
                begin
                        t:=t+s[i];
                end;
        end;
        for i:=1 to n do
        begin
                read(a[i]);
        end;
        if t='xor' then
        begin
                for i:=1 to n do
                begin
                        j:=a[i];
                        for k:=16 downto 1 do
                        begin
                                jl[k]:=j mod 2;
                                j:=j div 2;
                        end;
                        if i>1 then
                        begin
                                x:=0;
                                y:=1;
                                while y<=16 do
                                begin
                                        if tree[x,1-jl[y]]=0 then
                                        begin
                                                x:=tree[x,jl[y]];
                                                inc(y);
                                        end
                                        else
                                        begin
                                                x:=tree[x,1-jl[y]];
                                                inc(y);
                                        end;
                                end;
                                writeln(a[i] xor bzz[x],' ',gs[x]);
                        end;
                        insert(0,1);
                end;
        end
        else
        if t='and' then
        begin
                for i:=1 to n do
                begin
                        x:=a[i] div mi[8];
                        y:=a[i] mod mi[8];
                        p:=-maxlongint;q:=0;
                        if i>1 then
                        begin
                                for j:=0 to mi[8]-1 do
                                if g[j,y]>0 then
                                begin
                                        k:=(x and j)*mi[8]+f[j,y];
                                        if k>p then
                                        begin
                                                p:=k;
                                                q:=g[j,y];
                                        end
                                        else
                                        if k=p then inc(q,g[j,y]);
                                end;
                                if kind=1 then writeln(p,' ',q)
                                else writeln(p);
                        end;
                        for j:=0 to mi[8]-1 do
                        begin
                                k:=j and y;
                                if k>f[x,j] then
                                begin
                                        f[x,j]:=k;
                                        g[x,j]:=1;
                                end
                                else
                                if k=f[x,j] then inc(g[x,j]);
                        end;
                end;
        end
        else
        begin
                for i:=1 to n do
                begin
                        x:=a[i] div mi[8];
                        y:=a[i] mod mi[8];
                        p:=-maxlongint;q:=0;
                        if i>1 then
                        begin
                                for j:=0 to mi[8]-1 do
                                if g[j,y]>0 then
                                begin
                                        k:=(x or j)*mi[8]+f[j,y];
                                        if k>p then
                                        begin
                                                p:=k;
                                                q:=g[j,y];
                                        end
                                        else
                                        if k=p then inc(q,g[j,y]);
                                end;
                                if kind=1 then writeln(p,' ',q)
                                else writeln(p);
                        end;
                        for j:=0 to mi[8]-1 do
                        begin
                                k:=j or y;
                                if k>f[x,j] then
                                begin
                                        f[x,j]:=k;
                                        g[x,j]:=1;
                                end
                                else
                                if k=f[x,j] then inc(g[x,j]);
                        end;
                end;
        end;
end.
end.


原文地址:https://www.cnblogs.com/RainbowCrown/p/11148348.html