码迷,mamicode.com
首页 > 其他好文 > 详细

CF986C AND Graph

时间:2019-02-25 14:55:39      阅读:215      评论:0      收藏:0      [点我收藏+]

标签:直接   标记   mes   复杂   class   div   amp   rap   i++   

半年前做的一道题现在还是不会

x&y=0

意味着,x的补集的子集都是和x直接相连的

不妨令图中的点数就是2^n

那么可以直接从x^((1<<n)-1)开始记忆化爆搜,路上遇到的都是和x直接相连的

如果遇到一个在给出集合里的数t,就从这个点额外再开一层,t^((1<<n)-1)再开始爆搜

这样,如果两个点直接或者间接相连,那么一定可以从任意一个点出发搜出整个连通块,并对每个点打上标记

总共的状态数是2^22。复杂度有保证

 

loc只是一个理解,其实不需要

#include<bits/stdc++.h>
using namespace std;
const int N=(1<<22)+10;
int exi[N];
bool vis[N];// zuo i youwu vis
bool has[N];// you i youwu vis
int cnt,mx,len,up;
int a[N];
int n,m;
void dfs(int x,int loc){
    //cout<<x<<" now "<<cnt<<endl;
    if(loc){
        if(has[x]) return;
        has[x]=1;
        if(exi[x]) {vis[exi[x]]=1;dfs(a[exi[x]],0);}
        for(int i=0;(1<<i)<=x;i++){
            if(x&(1<<i)){
                dfs(x^(1<<i),1);
            }
        }
    }
    else{
        vis[exi[x]]=1;dfs(up^x,1);
    }
}
int main()
{
    /*lg[0]=0;
    for(int i=1;i<=N-5;i++) lg[i]=(i>>(lg[i-1]+1))?lg[i-1]+1:lg[i-1];*/
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d",&a[i]),exi[a[i]]=i,mx=max(mx,a[i]);
    }
    for(int i=0;i<=23;i++){
        if((1<<i)>mx) break;
        len=i+1;
    }
    up=(1<<len)-1;//cout<<" up "<<up<<endl;
    for(int i=1;i<=m;i++){
        if(!vis[i]) {
            //cout<<"here go "<<i<<" "<<a[i]<<endl;
            cnt++;dfs(up^a[i],1);
        }
    }
    printf("%d",cnt);return 0;
}

 

CF986C AND Graph

标签:直接   标记   mes   复杂   class   div   amp   rap   i++   

原文地址:https://www.cnblogs.com/Miracevin/p/10430800.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!