CF1221Gグラフと数値(および除外、検索、FMT)

エドゥが、これはG EFよりも簡単であることを持っていると思う......

人々が話題にする理由を私は知らない\(M = 0 \)を、それらに出て、特に最初の文を。

これは、少なくとも一つの必要\(0 \)を少なくとも一つ、\(1 \) 少なくとも一つの\(2 \)なし- 、および除外波、プログラムの合計数に\(0 \) -なし\(1 \) -ない\(2 \) +無\(01 \) +無\(02 \) +無\(12 \) +無\(012 \)

いいえ\(0 \)と無\(2 \)は、最終的な議論を入れ、実に比較しません。

いいえ\(1 \) すべての数字が同じで、リンク・ブロックをリンクブロックを考慮し、プログラムナンバーである(CNT 2 ^ {} \)\ない\(CNTは\)中国ユニコムのブロック数です。

いいえ\(01 \)だけで、\(2 \)リンクはサイド(シングルポイント)をブロックしていない場合、は、もちろん、あなたは簡単に、すべての数字があるそうユニコムブロックに置くことはできません\(1 \を)プログラムナンバー\(CNT2 2 ^ {} \) \(\ CNT2)はチャイナユニコムの単一点のブロックの数です。

いいえ(\ 02 \)のみであり、\(1 \)は、この図は、黒と白の着色方式の数に相当しません。黒と白の染色場合、プログラム番号である(CNT 2 ^ {} \)\、そうでなければ\(0 \)

いいえ\ない(12 \) およびno (\ 01 \)同じ。プログラム番号は、\(CNT2 2 ^ {} \)

いいえ\(\ 012)は、以来\(m個\ NE 0 \) 明らかに不可能ではありません。プログラム番号\(0 \)

そして、何の考慮(0 \)\プログラム番号(なし\(2 \)が同じではありません)。

データ範囲は、バイナリ検索私たちを聞かせて、明らかです。私たちは、後半を検索することもできます。

各有効の後半(つまり、どの2つがされているためにない\(0 \)隣接点の)、何点の最初の部分をすることができない(0 \)\私たちが知っています。

現在選択さの半分にそれを変更\(0 \)のように設定ポイント\(S \) プログラムの種類数の後半\(val_S \) (これは私が書いたものです)

条件を満たす(Sは\)\点のサブセットの補数を選択することができません。

実際には、の補数\(ヴァル\)を追加します\(1 \)を、高次元の検索サフィックスの後にそれを行うと、実際に取得することができます\(val_S \) 理解することは難しいことではありません。

そしてそのと相まって、すべての法的スキームのために、前半を検索する\(ヴァル\)ライン上。

時間の複雑さは、前半部を有する場合\(T \)は複雑である点\(O(TT ^ 2 + 2 ^ {N T})\)

私は怠惰なので、私がかかった\(T = \ FRAC {N-2}} {\)を場合、実際には、\(T \)は、十分に制御、実行されるべきである\(N-50 = \) (テイク)(\ = 23 \ Tを、おそらく+ CF神のマシンは問題になりません3e8,3.5s)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int maxn=1048576;
#define MP make_pair
#define PB push_back
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline ll read(){
    char ch=getchar();ll x=0,f=0;
    while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return f?-x:x;
}
int n,m,cnt,cnt2,bar,lim;
ll e[40],ans,val[maxn];
bool ind[40],vis[40],col[40],flag=true;
void dfs(int u){
    vis[u]=true;
    FOR(v,0,n-1) if((e[u]>>v)&1){
        if(!vis[v]) col[v]=col[u]^1,dfs(v);
        else{
            if(col[v]!=(col[u]^1)) flag=false;
        }
    }
}
void dfs1(int dep,ll st,ll used){
    if(dep==bar) return void(val[(~st)&(lim-1)]++);
    dfs1(dep-1,st,used);
    if(!((st>>dep)&1)) dfs1(dep-1,st|e[dep],used|1<<dep);
}
void dfs2(int dep,ll st,ll used){
    if(dep==bar+1) return void(ans-=2*val[used&(lim-1)]);
    dfs2(dep+1,st,used);
    if(!((st>>dep)&1)) dfs2(dep+1,st|e[dep],used|1<<dep);
}
int main(){
    n=read();m=read();
    if(!m) return puts("0"),0;
    FOR(i,0,n-1) ind[i]=true;
    FOR(i,1,m){
        int u=read()-1,v=read()-1;
        e[u]|=1ll<<v;e[v]|=1ll<<u;
        ind[u]=ind[v]=false;
    }
    FOR(i,0,n-1) if(ind[i]) cnt2++;
    FOR(i,0,n-1) if(!vis[i]) cnt++,dfs(i);
    ans=(1ll<<n)-(1ll<<cnt)+(1ll<<cnt2)+(1ll<<cnt2)+(flag?1ll<<cnt:0);
    bar=(n-1)/2;lim=1<<(bar+1);
    dfs1(n-1,0,0);
    for(int i=1;i<lim;i<<=1)
        for(int j=0;j<lim;j+=i<<1)
            FOR(k,0,i-1) val[j+k]+=val[i+j+k];
    dfs2(0,0,0);
    printf("%lld\n",ans);
}

おすすめ

転載: www.cnblogs.com/1000Suns/p/11566940.html