• CF1105E Helping Hiasat


    cf

    luogu

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

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

    upd:上面两个信息可以不用高维前缀和,因为子集max计算是可以算重复贡献的,所以一个(i)可以由(i-lowbit(i))(i-hignbit(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
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    javascript内部原理篇[__proto__和prototype]
    javascript内部原理篇[进入上下文之前javascript所做的工作]
    jQuery Wookmark-2 jQuery动态表格插件的效果展示
    jQuery Wookmark
    jQuery Handsontable【jQuery插件-一个非常酷的可编辑表格】
    C#实现union以及lock的使用
    VC++编程中常用的字符串转换函数
    浅谈__declspec(dllexport)和__declspec(dllimport)
    C++宏定义中"#"与"##"的妙用
    Log4Cplus的介绍
  • 原文地址:https://www.cnblogs.com/smyjr/p/11594953.html
Copyright © 2020-2023  润新知