9.12 T2 技能大赛

· · 个人记录

题意

数据范围

解析

0.题意转化

1.折半设计

const int maxn=37,maxm=1297;
int n,m;
int zuo,you; 

ll cost[maxn];

int req[maxn];//对应点,如果在左边没有选,在右边必须选谁。这是个 state。

bitset<maxm> has;//判重边 
bitset<maxm> zuoreq,youreq;//所需的 
bitset<maxm> ava[maxn];//能覆盖的 

il void init(){
    n=rd(),m=rd(),mod=rd();

    For(i,0,n-1) cost[i]=rd();

    zuo=n>>1,you=n-zuo;
    //0~zuo-1 | zuo~n-1 (-zuo/+zuo ahead)
    //          0~you-1
    ri int u,v,hs;
    For(i,1,m){
        u=rd()-1,v=rd()-1;
        if(u>v) swap(u,v);
        hs=u*36+v;
        if(has[hs]) --i,--m;
        else{
            has[hs]=1;
            if(u<zuo && v<zuo) zuoreq[i]=1;
            else if(u>=zuo && v>=zuo) youreq[i]=1;
            else req[u]|=(1<<(v-zuo));//肯定是 u 在左,v 在右
            ava[u][i]=ava[v][i]=1;
        }
    }
    return;
}

il int lowbit(int x){return x&(-x);}

const int maxsta=1<<18;
int zuofull;
bitset<maxm> avazuo[maxsta];
ll costzuo[maxsta];
bitset<maxsta> viszuo;

il void dfszuo(int sta){
    if(!sta) return;
    ri int low=lowbit(sta),lg=log2(low),to=sta^low;
    if(!viszuo[to]) viszuo[to]=1,dfszuo(to);
    avazuo[sta]=avazuo[to]|ava[lg];
    costzuo[sta]=costzuo[to]*cost[lg]%mod;
    return;
}

int youfull;
bitset<maxm> avayou[maxsta];
ll costyou[maxsta];
bitset<maxsta> visyou;

il void dfsyou(int sta){
    if(!sta) return;
    ri int low=lowbit(sta),lg=log2(low),to=sta^low;
    if(!visyou[to]) visyou[to]=1,dfsyou(to);
    avayou[sta]=avayou[to]|ava[lg+zuo];
    costyou[sta]=costyou[to]*cost[lg+zuo]%mod;
    return;
}

int reqsta[maxsta];
bitset<maxm> forcheck;

bitset<maxsta> filped;

ll sum[maxsta];
ll ans;
il void work(){
    zuofull=(1<<zuo)-1,costzuo[0]=1;
    For(i,0,zuofull) if(!viszuo[i]) viszuo[i]=1,dfszuo(i);

    youfull=(1<<you)-1,costyou[0]=1;
    For(i,0,youfull) if(!visyou[i]) visyou[i]=1,dfsyou(i);

    //下面先对左边每个 sta 求一下它需求的补集。
    ri int forfind,low;
    For(i,0,zuofull){
        forcheck=zuoreq&avazuo[i];
        if(forcheck!=zuoreq) reqsta[i]=-1;
        else{
            forfind=zuofull^i;//这些是没选的。
            while(forfind){
                low=lowbit(forfind);
                reqsta[i]|=req[(int)log2(low)];
                forfind^=low;
            }
        }
    }

    //然后吗,我们知道超集和求不了,所以转换一下:把这些补集反转,问题就变成了求这些反集的子集和
    For(i,0,zuofull)
        if(~reqsta[i])
            reqsta[i]=youfull^reqsta[i];

    //接下来我们得相应地把和 you 有关的东西全部反转过来...顺便把子集和初始化一下。
    For(i,0,youfull){
        forcheck=youreq&avayou[i];
        if(forcheck!=youreq) continue;//你没用。
        //你肯定有用;那么我们现在把你反转扔进 sum。
        sum[i^youfull]=costyou[i];
    }

    //处理子集和 
    For(i,0,you-1)
        For(sta,0,youfull)
            if(sta&(1<<i))
                add(sum[sta],sum[sta^(1<<i)]);

    For(i,0,zuofull)
        if(~reqsta[i])
            add(ans,costzuo[i]*sum[reqsta[i]]%mod);

    wt(ans);
    return;
}

2.暴搜

总结与反思

1.知识点

2.解题中的失误

3.其他