HDU4025 Equation of XOR [二分+状态压缩]

  ai取值范围0~1,xi取值范围0~3,所以最后异或的结果不会超过两位二进制。所以可以用一个60位的数保存30个式子的值,然后m的范围是小于22,二分一下就可以了,4^11=4*10^6,结果存下来排个序然后二分找一下就可以了。

  

#include <stdio.h>
#include <string.h>
#include <algorithm>
typedef __int64 LL;
int cas,n,m,ai[35][30],si[30][4];
LL ans,tmp[1<<22+2];
int sum[1<<22+2];
int size,nsize;

int binser(LL x){
    int low=0,high=size,mid;
    for(;;){
        mid=(low+high)/2;
        if(mid==low)break;
        if(tmp[mid]<=x)low=mid;
        else high=mid;
    }
    return tmp[mid]==x?sum[mid]:0;
}
LL cal(int p,int x){
    LL ans=0;
    for(int i=1;i<=n;i++)
        ans=(ans<<2)+(ai[i][p]*x);
    return ans;
}
void dfs(int p,LL now,int full,int id){
    if(p>full)id==0?tmp[size++]=now:ans+=binser(now);
    else for(int i=1;i<=si[p][0];i++)
        dfs(p+1,now^cal(p,si[p][i]),full,id);
}
int main(){
    //freopen("test.in","r",stdin);
    scanf("%d",&cas);
    while(cas--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%d",&ai[i][j]);
        for(int i=1;i<=m;i++){
            scanf("%d",&si[i][0]);
            for(int j=1;j<=si[i][0];j++){
                scanf("%d",&si[i][j]);
            }
        }
        ans=size=0;
        int halfm=m/2;
        dfs(1,0LL,halfm,0);

        std::sort(tmp,tmp+size);
        nsize=size,size=1,sum[0]=1;
        for(int i=1;i<nsize;i++){
            if(tmp[i]!=tmp[i-1]){
                tmp[size]=tmp[i],sum[size]=1,size++;
            }else sum[size-1]++;
        }
        dfs(halfm+1,0LL,m,1);

        printf("%I64d\n",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/swm8023/p/2659363.html