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

CF1105E Helping Hiasat

时间:2019-09-26 23:08:59      阅读:102      评论:0      收藏:0      [点我收藏+]

标签:i+1   turn   unsigned   最大   force   while   操作   之间   lin   

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

标签:i+1   turn   unsigned   最大   force   while   操作   之间   lin   

原文地址:https://www.cnblogs.com/smyjr/p/11594953.html

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