cf #637 (Div. 2) D. Nastya and Scoreboard

这题看着就是一道dp,不过始终没找到什么合适的方法(太菜了) 一开始想着用string类型记录所有状态然后强行比较大小(然后发现string的比较和加运算都是o(n)的) 也就是搞了个N^3的算法 肯定gg了  

赛后看了一下别人交的代码 感觉还是思维太差了(当时始终想不到怎么记录dp的路径)

首先我们要从低位向高位dp,为啥呢,因为在比较大小的时候是从高位开始逐一的比较,如果从低位可以推到某个高位的话,说明这个高位一定是可行的,相反我们无法通过比较低位判断大小。

我们用f[i][j] 表示以第 i 个位置开始的后缀 使用 j 根棍子的可行性

边界条件 f[n+1][0]=true 

递推式 f[i][j]|=f[i+1][j-x]  表示当第 i 个位置的数使用x根棍子时

然后我们在正着来一遍推出答案就行了

#include<bits/stdc++.h>
using namespace std;
bool f[2004][2004];
int ans[2004],a[2005];
int s[10]={0b1110111,0b0010010,0b1011101,0b1011011,0b0111010,0b1101011,0b1101111,0b1010010,0b1111111,0b1111011};
int main(){
	int n,k;
	scanf("%d%d",&n,&k);
	char g[10];
	for(int i = 1; i <= n; i++){
		scanf("%s",g);
		int len = strlen(g);
		for(int j = 0; j < len; j++) a[i]=a[i]*2+(g[j]=='1');
	}
	f[n+1][0]=true;
	for(int i = n; i >= 1; i--){
		for(int j = 0; j <= 9; j++){
			if((s[j]&a[i])==a[i]){
				int m = 0;
				for(int h = 0; h < 7; h++) if(!((a[i]>>h)&1)&&((s[j]>>h)&1)) m++;
				for(int c = m; c <= k; c++) f[i][c]|=f[i+1][c-m];
			}
		}
	} 
	if(!f[1][k]){
		puts("-1");
		return 0;
	}
	for(int i = 1; i <= n; i++){
		for(int j = 9; j >= 0; j--){
			if((s[j]&a[i])==a[i]){
				int m = 0;
				for(int h = 0; h < 7; h++) if(!((a[i]>>h)&1)&&((s[j]>>h)&1)) m++;
				if(k>=m&&f[i+1][k-m]) {ans[i]=j,k-=m;break;}
			}
		}
	}
	for(int i = 1; i <= n; i++) printf("%d",ans[i]);
	return 0;
}
原创文章 85 获赞 103 访问量 2493

猜你喜欢

转载自blog.csdn.net/weixin_43824564/article/details/105728724