bzoj1553: XOR网络

Description

  计算给定范围内有多少种输入可以使输出为1。 我们假设3 < n < 100, 3 < m < 3000,而且网络中的门是用1到m之间的数任意编号的。

Input

文件第一行包含三个整数,分别表示输入的个数,门的个数,连接到输出的门的编号。以下的m行描述网络中的连接情况。第I行表示第I个门的两个输入,两个输入为范围[-n,m]之间的一个整数。如果输入是网络的第k个输入,则连接的描述是一个整数-k,如果输入是第j个门,则连接的描述是一个整数j。以下两行各有一个n位二进制串,表示输入的上限和下限。

Output

包含一个整数,表示给定范围内有多少种输入可以使输出为1。
由异或的性质,拓扑排序并处理出最终输出等于哪些输入异或起来,于是转成区间内有几个二进制数和指定数的按位与有奇数个1,可以数位dp
#include<cstdio>
#include<bitset>
typedef unsigned long long u64;
int n,m,o;
int es[6007],enx[6007],e0[3007],deg[3007],q[3007],ql=0,qr=0,ep=2;
std::bitset<102>st[3007];
int S[107];
char l[107],r[107];
void ae(int a,int b){
    es[ep]=b;enx[ep]=e0[a];e0[a]=ep++;
    ++deg[b];
}
struct num{
    u64 a,b;
    num(u64 _a,u64 _b):a(_a),b(_b){};
    num(u64 _a=0):a(0),b(_a){}
    void print(){
        int ss[107],sp=0;
        u64 v1=a>>32,v2=a&0xffffffffll;
        u64 v3=b>>32,v4=b&0xffffffffll;
        while(v1|v2|v3|v4){
            v2+=v1%10<<32;v1/=10;
            v3+=v2%10<<32;v2/=10;
            v4+=v3%10<<32;v3/=10;
            ss[sp++]=v4%10;v4/=10;
        }
        if(!sp)putchar('0');
        while(sp)putchar('0'+ss[--sp]);
    }
};
num operator+(num x,num y){
    u64 c=x.b+y.b;
    return num(x.a+y.a+(c<x.b),x.b+y.b);
}
num operator-(num x,num y){
    return num(x.a-y.a-(x.b<y.b),x.b-y.b);
}
num f[107][2][2];
void pre(){
    f[n+1][0][0]=1;
    for(int i=n;i;--i){
        f[i][0][0]=f[i][1][S[i]]=f[i+1][0][0]+f[i+1][1][0];
        f[i][0][1]=f[i][1][S[i]^1]=f[i+1][0][1]+f[i+1][1][1];
    }
}
num cal(char*s,bool e){
    for(int i=1;i<=n;++i)s[i]-='0';
    int d=0;
    num ans=0;
    for(int i=1;i<=n;++i){
        if(s[i])ans=ans+f[i][0][d^1];
        if(S[i])d^=s[i];
    }
    if(e){
        int d=0;
        for(int i=1;i<=n;++i)if(S[i])d^=s[i];
        ans=ans+d;
    }
    return ans;
}
int main(){
    scanf("%d%d%d",&n,&m,&o);
    for(int i=1,a,b;i<=m;++i){
        scanf("%d%d",&a,&b);
        if(a<0)st[i].flip(-a);
        else ae(a,i);
        if(b<0)st[i].flip(-b);
        else ae(b,i);
    }
    for(int i=1;i<=m;++i)if(!deg[i])q[++qr]=i;
    while(ql!=qr){
        int w=q[++ql];
        for(int i=e0[w];i;i=enx[i]){
            int u=es[i];
            st[u]^=st[w];
            if(!--deg[u])q[++qr]=u;
        }
    }
    for(int i=1;i<=n;++i)S[i]=st[o][i];
    scanf("%s%s",l+1,r+1);
    pre();
    (cal(r,1)-cal(l,0)).print();
    return 0;
}
原文地址:https://www.cnblogs.com/ccz181078/p/6254189.html