題意:一個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; }
