这题看着就是一道dp,不过始终没找到什么合适的方法(太菜了) 一开始想着用string类型记录所有状态然后强行比较大小(然后发现string的比较和加运算都是o(n)的) 也就是搞了个N^3的算法 肯定gg了
赛后看了一下别人交的代码 感觉还是思维太差了(当时始终想不到怎么记录dp的路径)
首先我们要从低位向高位dp,为啥呢,因为在比较大小的时候是从高位开始逐一的比较,如果从低位可以推到某个高位的话,说明这个高位一定是可行的,相反我们无法通过比较低位判断大小。
我们用 表示以第 i 个位置开始的后缀 使用 j 根棍子的可行性
边界条件
递推式 表示当第 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;
}