• 暑假集训Day3 M(数学异或问题)


     

    很经典的异或问题,对于这种异或计数问题,通常的思想是把它放到一棵二进制树中去看,二进制树中的第 i 层,对应的是一个数中的从高往低数第 i 位的取值,我们需要从根节点开始向下递归去确定取值。

    对于一棵二进制树(它可能是原树的一颗子树),如果它的左右孩子是完全一样的,意味着当前位取0或者1都是可以的不影响结果,我们就将ans*=2;

    如果不是完全一样的,说明在这一位上必须有所区分,要么取0要么取1,那么,如果在左孩子里出现了右孩子里出现的数,那就不行了,因为当前位只能有一个取值,不能既可以0又可以1.

    二进制树在解决异或问题中非常常见,本质是从最高位一位一位的计数!包括位运算计数问题,也可能会用到二进制树的方法!

     1 #include "bits/stdc++.h"
     2 using namespace std;
     3 typedef long long LL;
     4 const int MAX=7e4;
     5 const LL MOD=1e9+7;
     6 LL n,m,a[MAX],ans;
     7 bool flag;
     8 bitset <MAX> bs;
     9 void dfs(int lft,int now){
    10     if (now==0) return;
    11     LL len=1<<(now-1);
    12     bool ck=true;int i,j;
    13     for (i=1;i<=len;i++)
    14         if (a[lft+i-1]!=a[lft+len+i-1])
    15             ck=false;
    16     if (ck){
    17         ans=ans*2%MOD;
    18         dfs(lft,now-1);
    19     }
    20     else{
    21         bs.reset();
    22         for(i=1;i<=len;i++) bs[a[lft+i-1]]=true;
    23         for(i=1;i<=len;i++)
    24             if (bs[a[lft+len+i-1]]){
    25                 flag=false;
    26                 return;
    27             }
    28         dfs(lft,now-1);
    29         dfs(lft+len,now-1);
    30     }
    31 }
    32 int main(){
    33     int i,j;
    34     scanf("%lld%lld",&n,&m);
    35     for (i=1;i<=(1<<n);i++)
    36         scanf("%lld",a+i);
    37     flag=true; ans=1;
    38     dfs(1,n);
    39     if (flag) printf("%lld",ans);
    40     else printf("0");
    41     return 0;
    42 }
  • 相关阅读:
    转帖:linux 下注册apache开机自启动
    apache 编译 rewrite 模块
    Skyline开发入门(C#)
    matlab的m文件怎么集成到vs里?
    C#打包安装与卸载
    OnClick与OnClientClick的时序和条件
    javascript弹出窗口代码大全
    .NET开发人员必知的八个网站
    [转] GIS算法源码集合
    最短路径算法——Dijkstra and Floyd算法
  • 原文地址:https://www.cnblogs.com/keximeiruguo/p/16463899.html
Copyright © 2020-2023  润新知