传送门:https://codeforces.com/contest/1221/problem/G

sol:

感觉这个G题还挺好搞的……

首先同时有$0$,$1$,$2$正面统计好像不大好统计

那就反过来

总方案数$2^n$

然后要减去没有$0$的方案,没有$1$的方案,没有$2$的方案,加上没有$0,1$的方案,没有$0,2$的方案,没有$1,2$的方案,减去没有$1,2,3$的方案

我们分开讨论

显然 没有$0$的方案数和没有$2$的方案数是等价的

没有$0$的方案:考虑把填$0$设为$1$,其他设为$0$,$2^{40}$好像有点大 拆半找 然后对于一个确定的前半部分 后半部分不能选的方案就确定了,然后枚举后半部分取法 然后加上合法的前半边的计数就行了

没有$1$的方案:即一个联通块内同时填$0$或$1$,设联通块数为$c$,答案为$2^c$

没有$0,1$的方案:即只有2的方案,这个时候可以发现,除了孤点,其他的点都填入$1$,只需要统计孤点的数量,设为$cnt$,答案为$2^cnt$

没有$0,2$的方案:即只有1的方案,也就是说这时候是0101……这样交替填入。如果有奇环则不合法,如果没有奇环,答案为$2^c$,否则是$0$

没有$1,2$的方案:只有0的方案,这时候和只有$2$的方案等价

没有$0,1,2$的方案 如果$m=0$ 答案为$2^n$,否则为$0$

思路大概就这样233

代码可能有点麻烦

Code:

#include <bits/stdc++.h>
using namespace std;
int N,M;
int vis[55];
vector <int> qwq[40];
long long Right[45],cntRight[1<<20];
long long Onl(){
    long long ans=0;
    for (int i=0;i<N;i++)
        if (qwq[i].size()==0) ans++;
    return ans;
}
void dfs(int Now,int x){
    if (vis[Now]) return;
    vis[Now]=x;
    for (int i=0;i<qwq[Now].size();i++)
        dfs(qwq[Now][i],3-x);
}
long long GetComponents(){
    memset(vis,0,sizeof(vis));
    long long ans=0;
    for (int i=0;i<N;i++)
        if (!vis[i]){
            ans++;
            dfs(i,1);
        }
    return ans;
}
long long Get02(){
    long long m1=min(N,20);
    long long m2=N-m1;
    memset(cntRight,0,sizeof (cntRight));
    for (long long i=0;i<(1ll<<m1);i++){
        long long Nowmas=0;
        bool flag=true;
            for (int j=0;j<m1;j++){
                if ((i&(1ll<<j))==0) continue;
                    if (Nowmas&(1ll<<j))
                        flag=false;
                    Nowmas|=((1ll<<j)|Right[j]);
            }
        if (flag)
            cntRight[Nowmas>>m1]++;
    }
    for (int i=0;i<m2;i++)
        for (int j=0;j<(1<<m2);j++)
            if (j&(1ll<<i))
                cntRight[j]+=cntRight[j^(1ll<<i)];
    long long ans=0;
    for (long long i=0;i<(1<<m2);i++){
        long long Nowmas=0;
        bool flag=true;
        for (int j=m1;j<N;j++){
            if ((i&(1<<(j-m1)))==0) continue;
                if (Nowmas&(1ll<<j))
                    flag=false;
            Nowmas|=(1ll<<j)|Right[j];
        }
        if (flag)
            ans += cntRight[i^((1ll<<m2)-1)];
    }
    return ans;
}
bool Non_Odd(){
    memset(vis,0,sizeof(vis));
    for (int i=0;i<N;i++)
        if (!vis[i])
            dfs(i,1);
    for (int i=0;i<N;i++){
            for (int j=0;j<qwq[i].size();j++)
                if (vis[i]==vis[qwq[i][j]]) return false;
    }
    return true;
}
long long Pow(long long x,long long y){
    long long ans=1;
    for (;y;y>>=1){
        if (y&1) ans=ans*x;
        x=x*x;
    }
    return ans;
}
long long Calc(int Mask){
    if (Mask==0) return Pow(2,N);
    if (Mask==1||Mask==4) {return Get02();}
    if (Mask==2){return Pow(2,GetComponents());}
    if (Mask==3||Mask==6){return Pow(2,Onl());}
    if (Mask==5){if (Non_Odd()) return Pow(2,GetComponents());else return 0;}
    if (Mask==7) {if (M==0) return Pow(2,N);else return 0;}
}
int main(){
    scanf("%d%d",&N,&M);
    for (int i=0;i<M;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        --x;--y;
        qwq[x].push_back(y);
        qwq[y].push_back(x);
        Right[x]^=(1ll<<y);
        Right[y]^=(1ll<<x);
    }
    long long ans=0;
    for (int i=0;i<8;i++){
        if (__builtin_popcount(i)%2==0)
            ans+=Calc(i);
        else ans-=Calc(i);
    }
    cout<<ans;
    return 0;
}
02-11 13:15