• 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.
    
    
    
  • 相关阅读:
    解决chrome浏览器无法得到window.showModalDialog返回值的问题
    Javascript 中 null、NaN和undefined的区别
    Windows Server 2003 asp网页不能访问的常见问题
    关于SQLServer无法对数据库'XXX'执行删除,因为它正用于复制。错误:'3724' 的解决方案
    关于Gridview激发了未处理的事件“RowDeleting”错误的处理
    ASP.NET中实现文件下载功能
    C#中ref和out的作用和区别
    关于Pascal(帕斯卡)以及Camel(驼峰)命名法
    期末作业验收
    SDN第五次上机作业
  • 原文地址:https://www.cnblogs.com/RainbowCrown/p/11148348.html
Copyright © 2020-2023  润新知