SYZOJ 20220216 B 计分板

written on 2022-02-18

这是一道dp题

首先,我们可以稍微的用自己的语言描述一下题意:

有n个二进制数,对于每一个,找到满足条件的带权值的数,使得自己是这个数的子集,n个数相差的二进制数位相加的和恰好为k

经过思考,我们可以发现,题目有判断是否存在的要求,所以可以用可行性dp先进行处理

那么,如果存在,怎么满足最后组成的数最大呢?

发现从前往后顺次枚举是存在后效性的(选了这个数,可能后面就不能满足和为k)

于是倒序枚举,用可行性dp处理出所有的情况,对于每一次选的操作,看看后面是否有可以转移过来的,这样就可以满足题目所给的要求了

CODE

#include<bits/stdc++.h>
using namespace std;
const int d[]={119,18,93,91,58,107,111,82,127,123};
int n,m,a[2005];
int f[2005][2005];
int count_1(int x)
{
	int cnt=0;
	while(x)
	{
		cnt++;
		x&=(x-1);
	}
	return cnt;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		char ch[10];
		scanf("%s",ch);
		int len=strlen(ch);
		for(int j=0;j<len;j++) if(ch[j]=='1') a[i]|=(1<<(len-j-1));
	}
	f[n+1][0]=1;
	for(int i=n;i;i--)
	{
		for(int j=0;j<=9;j++)
		{
			if((a[i]&d[j])==a[i])
			{
				int cnt=count_1(a[i]^d[j]);
				for(int k=cnt;k<=2000;k++)
				{
					if(f[i+1][k-cnt]) f[i][k]=1;
				}
			}
		}
	}
	if(!f[1][m]) printf("-1"),exit(0);
	for(int i=1;i<=n;i++)
	{
		for(int j=9;j>=0;j--)
		{
			if((a[i]&d[j])==a[i])
			{
				int cnt=count_1(a[i]^d[j]);
				if(f[i+1][m-cnt])
				{
					printf("%d",j);
					m-=cnt;
					break;
				}
			}
		}
	}
}
posted @ 2022-07-31 17:12  Freshair_qprt  阅读(17)  评论(0编辑  收藏  举报