【WC模拟】Equation

23 篇文章 0 订阅
18 篇文章 0 订阅

Description

这里写图片描述
n,m<=10^5

Solution

考虑图论转化,既然每个变量最多只会出现两次,那么我们把出现两次的变量所在的or组看做点,每个出现两次的变量看做边,边权视这两个变量是否相同而定。(0或1)
根据题目条件我们每个点的度数最多为2,也就是只会出现环和链。
设Fi,j,k表示当前做到第i个点,异或值为j,上一位填的是k的方案数,转移显然。
最后分类讨论一下就行了,注意特判自环和没有出现的点。

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define rep(i,a) for(int i=last[a];i;i=next[i])
using namespace std;
typedef long long ll;
const int N=1e5+5,mo=1e9+7;
int n,m,l,x,y,ans,a[N][2],r[N],p[N],w[N];
int t[N*2],next[N*2],v[N*2],one[N],last[N];
int f[N][2][2],now[2],s[2],la[2];
bool bz[N];
void add(int x,int y,int z) {
    t[++l]=y;v[l]=z;next[l]=last[x];last[x]=l;
}
void dfs(int x,int y) {
    if (bz[x]) return;
    bz[x]=1;w[++w[0]]=x;
    rep(i,x) 
        if (t[i]!=y) {
            p[++p[0]]=v[i];
            dfs(t[i],x);            
        }
}
void dp_chain() {
    memset(f[1],0,sizeof(f[1]));
    if (one[w[1]]) f[1][1][1]=2,f[1][1][0]=f[1][0][0]=1;
    else f[1][1][1]=f[1][0][0]=1;
    fo(i,1,w[0]-1) {
        fo(j,0,1) 
            fo(k,0,1) 
                f[i+1][j][k]=0;
        fo(j,0,1)
            fo(k,0,1) 
                if (f[i][j][k]) 
                    fo(l,0,1) 
                        (f[i+1][j^(l|(p[i]^k))][l]+=f[i][j][k])%=mo;
    }
    s[0]=s[1]=0;
    la[0]=now[0];la[1]=now[1];
    if (one[w[w[0]]]) {
        fo(i,0,1) 
            fo(j,0,1)
                (s[i]+=f[w[0]][i][j])%=mo;
    } else fo(i,0,1) s[i]=f[w[0]][i][0];
    now[0]=((ll)la[0]*s[0]%mo+(ll)la[1]*s[1]%mo)%mo;
    now[1]=((ll)la[0]*s[1]%mo+(ll)la[1]*s[0]%mo)%mo;
}   
void dp_circle() {
    s[0]=s[1]=0;
    la[0]=now[0];la[1]=now[1];
    if (w[0]==1) {
        if (p[0]) s[p[1]]=2;
        else {
            if (one[w[1]]==1) s[0]=s[1]=1;
            else s[0]=1,s[1]=3;
        }
        now[0]=((ll)la[0]*s[0]%mo+(ll)la[1]*s[1]%mo)%mo;
        now[1]=((ll)la[0]*s[1]%mo+(ll)la[1]*s[0]%mo)%mo;
        return;
    }
    fo(st,0,1) {
        memset(f[1],0,sizeof(f[1]));
        if (st) f[1][1][0]=f[1][1][1]=1;
        else f[1][0][0]=f[1][1][1]=1;
        fo(i,1,w[0]-1) {
            fo(j,0,1) 
                fo(k,0,1) 
                    f[i+1][j][k]=0;
            fo(j,0,1)   
                fo(k,0,1) 
                    if (f[i][j][k]) 
                        fo(l,0,1) 
                            (f[i+1][j^(l|(p[i]^k))][l]+=f[i][j][k])%=mo;
        }
        int en=st^p[p[0]];
        fo(i,0,1) (s[i]+=f[w[0]][i][en])%=mo;
    }
    now[0]=((ll)la[0]*s[0]%mo+(ll)la[1]*s[1]%mo)%mo;
    now[1]=((ll)la[0]*s[1]%mo+(ll)la[1]*s[0]%mo)%mo;
}
int main() {
    freopen("equation.in","r",stdin);
    freopen("equation.out","w",stdout);
    scanf("%d%d",&n,&m);
    fo(i,1,n)
        for(scanf("%d",&y);y;y--) {
            scanf("%d",&x);
            if (!a[abs(x)][0]) a[abs(x)][0]=i*((x>0)?1:-1);
            else a[abs(x)][1]=i*((x>0)?1:-1);
        }
    ans=now[0]=1;
    fo(i,1,m) {
        if (!a[i][0]) {ans=ans*2%mo;continue;}
        if (!a[i][1]) {one[abs(a[i][0])]++;continue;}
        int x=a[i][0],y=a[i][1],z=x<0&&y>0||x>0&&y<0;
        add(abs(x),abs(y),z);add(abs(y),abs(x),z);
        r[abs(x)]++;r[abs(y)]++;
    }
    fo(i,1,n) 
        if (r[i]==1&&!bz[i]) {
            p[0]=w[0]=0;
            dfs(i,0);
            dp_chain();
        }
    fo(i,1,n) 
        if (!bz[i]) {
            p[0]=w[0]=0;
            dfs(i,0);
            dp_circle();
        }
    printf("%lld\n",(ll)ans*now[1]%mo);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值