题意:一个n个数码位的分数板,每一个数码位都是一个七段数码管,现在给出每个数码位的显示情况,问再点亮k段数码管的话能显示的最大的数是多少,如果不能构成一串数字,就输出-1.
答案允许有前导0,但是有前导0的时候答案长度必须要跟n一致
原题链接:https://codeforces.ml/contest/1341/problem/D
开始感觉是贪心去爆搜,但是显然这会T,所以想了几分钟后就果断放弃了爆搜的想法。后边想了个dp,dp[i][j]表示构造到第i位时点亮j根数码管能显示最大的数,但这个也有个问题,你dp的类型是数值的话2000位的大整数你肯定装不下,可是如果是string类型这么dp下来复杂度会达到O(n3),就在这里卡着我没想出一个好的解决办法。
后来比赛结束后看了下standing第一大佬的代码,不得不感叹大佬的nb,虽然也是dp,但是他是dp[i][j]表示从后面构造到第i位数码位时点亮j根数码管能否构成数字,然后从第一位数码位开始贪心构造就行了。
系统地说算法的步骤吧。
第一步:预处理0~9对应数码位字符串状态成整数(状态压缩)
第二步:输入数据,并处理出每一位当前数码位所对应的整数形式的状态
第三步:定义enable[i][j]表示从最后一位数码位往前构造到第i位数码位时点亮j根数码管能否构造出数字
第四步:设置enable[n+1][0] = true,这是dp初始状态,意义是开始构造数码位时点亮了0根数码管。
第五步:for i = n -> 1,然后第i个数码位可以构造出数字num的话就算出要点亮几根数码管diff,然后for j = diff -> k,如果enable[i+1][j-diff]是true,则enable[i][j] = true。也就是能从之前已构造好的数字上再构造出这个数字的话enablep[i][j]就可以设成真
第六步:如果enable[1][k] = false,也就是说构造到第1位时点亮k段数码管无法成功构造成数字的话那么我们就输出-1
第七步(如果没输出-1):根据enable我们可以轻松构造出答案的字符串
AC代码:
#include <bits/stdc++.h> #define rep(i, l, r) for(long long i=l; i<=r ;i++) using namespace std; typedef long long ll; typedef pair<int, int> PII; typedef vector<int> VI; ll gcd(ll n, ll m) { return n % m == 0 ? m : gcd(m, n % m);} const int Maxn = 2e3 + 10; bool enable[Maxn][Maxn]; string Number[10] = {"1110111", "0010010", "1011101", "1011011", "0111010", "1101011", "1101111", "1010010", "1111111", "1111011" }; int val[10]; int dval[Maxn]; void Ini() { rep(i, 0, 9) rep(j, 0, 6) if(Number[i][j] == '1') val[i] |= 1 << (7-j-1); } void Input(int& n, int& k) { cin>>n>>k; rep(i, 1, n){ string s; cin>>s; rep(j, 0, 6) if(s[j] == '1') dval[i] |= 1 << (7-j-1); } } void solve(int n, int k) { enable[n+1][0] = true; for(int i=n; i>=1 ;i--) for(int j=9; j>=0 ;j--){ if((val[j] & dval[i]) == dval[i]){ int diff = __builtin_popcount(val[j] ^ dval[i]); for(int kk=diff; kk<=k ;kk++) enable[i][kk] |= enable[i+1][kk-diff]; } } if(!enable[1][k]){ cout<<-1<<endl; return; } string ans = ""; int remain = k; for(int i=1; i<=n ;i++) for(int j=9; j>=0 ;j--){ if((val[j] & dval[i]) == dval[i]){ int diff = __builtin_popcount(val[j] ^ dval[i]); if(enable[i+1][remain - diff]){ ans += j + '0'; remain -= diff; break; } } } cout<<ans; } int main() { ios::sync_with_stdio(false); //freopen("data.txt", "r", stdin); //freopen("output.txt", "w", stdout); Ini(); int n, k; Input(n, k); solve(n, k); return 0; }