[机房测试] 异或

Description

对于一个长为 \(n\) 且值域为 \([0,2^m)\) 的数列 \(a_i\), 定义 \(p_i\) 等于使得 \(i\) 异或 \(a_j\) 取最大值时的位置 \(j\)。现给定长 \(2^m\) 的数列 \(p_i\),求有多少种 \(a_i\) 能得到 \(p_i\)

Solution

知道 \(a\) 来求 \(p\),无非就是建好 01-Trie 然后贪心地走,那么一个下标实际上就唯一对应了一种匹配的路径。若干个 \(p\) 相同,就说明了 Trie 上存在一些位置,它们的转移是惟一的。具体而言,我们按位考虑,将区间分为两段,前一段的当前位全是 \(0\),后一段全是 \(1\)。如果两段中存在 \(p\) 是相同的,那么就说明转移是唯一的,如果不唯一,根据贪心策略转移一定不一样,\(p\) 就不可能相同。但是我们并不能确定该位是什么,所以把答案乘二。否则,就分别递归两个区间。

考虑无解的情况。显然必须每个 \(i\in[1,n]\) 都必须在 \(p\) 中出现,否则无解。其次,如果两段存在相同元素,那么两段必须完全相同。

#include<stdio.h>
#include<algorithm>
#include<map>
using namespace std;

inline int read(){
    int x=0,flag=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')flag=0;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
    return flag? x:-x;
}

const int N=17;
const int Mod=1e9+7;

long long ans=1;
int n,m,rg,p[1<<N];
bool ext[1<<N];

void Solve(int lf,int rf){
    if(lf==rf) return ;
    int mid=(lf+rf)>>1;
    map<int,bool> S; bool tag=0; S.clear(); 
    for(int i=lf;i<=mid;i++) S[p[i]]=1;
    for(int i=mid+1;i<=rf;i++) tag|=S[p[i]];
    if(tag){
        for(int i=lf;i<=mid;i++)
            tag&=(p[i]==p[i+rf-mid]);
        if(!tag){ans=0;return;}
        else ans=ans*2%Mod,Solve(lf,mid);
    }else Solve(lf,mid),Solve(mid+1,rf);
}

int main(){
    freopen("xor.in","r",stdin);
    freopen("xor.out","w",stdout);
    n=read(),m=read(),rg=1<<m;
    for(int i=0;i<rg;i++){
        p[i]=read();
        if(!ext[p[i]]) ext[p[i]]=1,n--;
    }
    if(n) return printf("0"),0;
    Solve(0,rg-1); printf("%lld",ans);
}
posted @ 2021-11-16 19:35  Kreap  阅读(49)  评论(0编辑  收藏  举报