1. 程式人生 > >【題解】[牛客網NOIP賽前集訓營-提高組(第二場)]C.集合劃分 狀壓DP

【題解】[牛客網NOIP賽前集訓營-提高組(第二場)]C.集合劃分 狀壓DP

題目連結
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述


在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
看了題解後還是沒寫對,只能去看Komachi大佬咋寫的了。

#include<cstdio>
#include<cstring>
const int N=18,MX=(1<<18)+5;
int n,m,k,ban[N][MX],pre[MX],f[MX];
int main()
{
	//freopen("in.txt","r",stdin);
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1,x;i<=m;i++)//一定給小s的集合 
    {
    	scanf("%d",&x);
    	for(int i=0;i<n;i++)
    	    if(x&(1<<i))
    	        ban[i][x]=1;//標記集合x中的i位
	}
	for(int i=0;i<n;i++)
	    for(int j=0;j<(1<<n);j++)
	        if(ban[i][j])
	            for(int k=0;k<n;k++)
	                if(!(j&(1<<k)))
	                    ban[i][j|(1<<k)]=1;
    f[0]=1;int S=(1<<n)-1;
	for(int i=0;i<(1<<n);i++)
	    if(f[i])
	    {
	    	int t=0;
	    	for(int j=0;j<n;j++)
	    	    t+=(i>>j)&1;
	    	t=1<<n-t-1;
	    	for(int j=0;j<n;j++)
	    	    if(!(i&(1<<j))&&((k&t)||(!ban[j][S^i])))
	    	        pre[i|(1<<j)]=i,f[i|(1<<j)]=1;
		}
	if(!f[S])puts("-1");
	else
	{
		memset(f,0,sizeof(f));
		for(int t=0,p=S;p;p=pre[p],t++)
		    if(k&(1<<t))
		    {
		    	int d=p^pre[p],i=p^S;
		    	for(int j=i;j;j=(j-1)&i)
		    	    f[d|j]=1;
		    	f[d]=1;
			}
		for(int i=1;i<(1<<n);i++)
		    putchar(f[i]^48);
		puts("");
	}
	return 0;
}

總結

狀壓DP+輸出方案