CF-div2-637-D. Nastya and Scoreboard | dp 贪心 记忆化搜索
思路1
思路2
dp + 贪心
-
预处理val[i][j] 第i个做成数字j点亮的花费
-
dp[i][cnt]表示 从后往前到第i个一共使用了cnt根能否凑出数字
假设第i个凑成数字j花费了cost,
那么dp[i][从后往前到第i个花费] |= dp[i+1][从后往前到第i+1个的花费-cost]
cost是能固定的,不固定的是前i个一共花费了多少
即当前这一轮凑成数字j的花费是固定的cost个,不固定的是 从后往前到第i个一共的花费
枚举 从后往前到第i个一共的花费了多少
那么dp[i][到i个一共的花费] |= dp[i+1][到i个一共的花费 - 第i个的cost花费]
dp代码
#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 2e3+100;
const string str[] = {"1110111","0010010","1011101","1011011","0111010","1101011","1101111","1010010","1111111","1111011"};
string s;
int val[maxn][10];
int dp[maxn][maxn];
void init(int pos){
for(int i=0;i<=9;i++){
bool flag=false;
int cnt=0;
for(int j=0;j<7;j++){
if(str[i][j]!=s[j]){
if(s[j]=='1'){
flag=true;
break;
}
cnt++;
}
}
if(flag) val[pos][i] = -1;
else val[pos][i] = cnt;
}
}
int main(){
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
cin>>s;
init(i);
}
dp[n+1][0]=true; //初态: 第n+1花费0个
for(int i=n;i>=1;i--){
for(int j=0;j<=9;j++){ //第i行凑出数字j
int cost = val[i][j]; //第i行花费cost凑出了数字j
if(cost == -1) {
dp[i][cost] = 0;
continue;
}
for(int t = cost;t<=k;t++){
dp[i][t] |= dp[i+1][t-cost];
}
}
}
if(!dp[1][k]) return 0*puts("-1");
//贪心找最大的
string ans;
for(int i=1;i<=n;i++){
for(int j=9;j>=0;j--){
if(val[i][j]!=-1 && dp[i+1][k-val[i][j]] == 1){
k -= val[i][j];
ans += to_string(j);
break;
}
}
}
cout<<ans<<endl;
return 0;
}