CF1105E Helping Hiasat

Posted smyjr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1105E Helping Hiasat相关的知识,希望对你有一定的参考价值。

cf

luogu

先将问题转换.由于一个网友要一直和他同名答案才能+1,所以对于一个改名的间隔,如果要选这个网友就不能选其他网友,所以对于两个1操作之间的所有网友分别相互连边.最后我们得到了一张图,现在问题是无向图最大独立集

\(n\le 40\),那就\(meet\ in\ the\ middle\),点集分为两半,然后分别暴力枚举集合,再枚举左边的某个集合,右边的集合能选当且仅当不存在和右边集合有连边的点,所以可以预处理出\(g_i\)表示右边超集为\(i\)的独立集大小最大值,可以高维前缀和实现.再预处理\(h_i\)表示左边独立集\(i\)在右边点的连边情况,同样可以高维前缀和.然后每次查一下就好了

#include<bits/stdc++.h>
#define LL long long
#define uLL unsigned long long
#define db double

using namespace std;
const int N=(1<<20)+10,M=45;
int rd()

    int x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9')if(ch=='-') w=-1;ch=getchar();
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48);ch=getchar();
    return x*w;

map<string,int> id;
bool v[M],mp[M][M];
int q,n,nn,stk[M],tp,zt[N],f[N],g[N],l2[N];
char cc[M];

int main()

    //////////////
    q=rd(),n=rd();
    while(q--)
    
        int op=rd();
        if(op==1)
        
            for(int i=1;i<=tp;++i)
                for(int j=i+1;j<=tp;++j)
                    mp[stk[i]][stk[j]]=mp[stk[j]][stk[i]]=1;
            while(tp) v[stk[tp]]=0,--tp;
        
        else
        
            scanf("%s",cc);
            if(!id[cc]) id[cc]=++nn;
            if(!v[id[cc]]) v[id[cc]]=1,stk[++tp]=id[cc];
        
    
    for(int i=1;i<=tp;++i)
        for(int j=i+1;j<=tp;++j)
            mp[stk[i]][stk[j]]=mp[stk[j]][stk[i]]=1;
    while(tp) v[stk[tp]]=0,--tp;
    for(int i=1;i<=n/2;++i)
    
        for(int j=1;j<=n-n/2;++j)
            zt[1<<(i-1)]|=mp[i][n/2+j]<<(j-1);
    
    for(int i=1;i<=1<<20;++i) l2[i]=l2[i>>1]+1;
    memset(f,-0x3f3f3f,sizeof(f));
    f[0]=0;
    for(int i=1;i<1<<(n/2);++i)
    
        int j=i^(i&(-i));
        bool ok=1;
        for(int k=1;ok&&k<=n/2;++k)
            ok=!(i>>(k-1)&1)||!mp[l2[i^j]][k];
        if(ok) f[i]=f[j]+1;
    
    memset(g,-0x3f3f3f,sizeof(g));
    g[0]=0;
    for(int i=1;i<1<<(n-n/2);++i)
    
        int j=i^(i&(-i));
        bool ok=1;
        for(int k=1;ok&&k<=n-n/2;++k)
            ok=!(i>>(k-1)&1)||!mp[l2[i^j]+n/2][k+n/2];
        if(ok) g[i]=g[j]+1;
    
    for(int j=1;j<1<<(n/2);j<<=1)
        for(int i=0;i<1<<(n/2);++i)
            if((i&j)==j) zt[i]|=zt[i^j];
    for(int j=1;j<1<<(n-n/2);j<<=1)
        for(int i=0;i<1<<(n-n/2);++i)
            if((i&j)==j) g[i]=max(g[i],g[i^j]);
    int ans=0,u=(1<<(n-n/2))-1;
    for(int i=0;i<1<<(n/2);++i)
        ans=max(ans,f[i]+g[u^zt[i]]);
    printf("%d\n",ans);
    return 0;

以上是关于CF1105E Helping Hiasat的主要内容,如果未能解决你的问题,请参考以下文章

CF494C Helping People

[CF494C]Helping People

$CF1105E Helping Hiasat$ 最大团

Codeforces #282 div 1 C Helping People 题解

最大团&优化

E - Helping the HR Gym - 102040E