[CF1221G] Graph And Numbers

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

sol:

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

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

那就反过来

总方案数2n

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

我们分开讨论

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

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

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

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

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

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

没有0,1,2的方案 如果m=0 答案为2n,否则为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;
}
复制代码

 

posted @   si_nian  阅读(351)  评论(1编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
欢迎阅读『[CF1221G] Graph And Numbers』
点击右上角即可分享
微信分享提示