題解 CF1428G Lucky Numbers (Easy Version and Hard Version)
阿新 • • 發佈:2020-10-18
這題沒有壓行就成 \(\texttt{Hard Version}\) 最短程式碼解了(
要知道這題那麼 \(sb\) 就不啃 \(D\) 和 \(E\) 了。
\(\texttt{Solution}\)
首先有一個非常簡單但是錯誤的多重揹包的想法:
讓分拆出來的 \(k\) 個數中,每一個數在十進位制下每一位都是 \(0, 3, 6\) 或 \(9\),於是對於第 \(x\) 位把 \(3k\) 個大小為 \(3 \times 10^x\), 價值為 \(F_x\) 的物品丟進多重揹包裡面,然後輸出答案。
這樣子顯然是不對的,例如輸入的數不是 \(3\) 的倍數就被卡掉了。因為還可能在某一位上價值是 \(0\)
有一個很顯然的結論:一定可以讓某一位上價不是 \(0, 3, 6, 9\) 的個數減少到 \(1\)。證明:如果有兩個非 \(0, 3, 6, 9\) 的數 \(a\) 和 \(b\)。如果 \(a + b > 9\), 那麼可以變成 \(9\) 和 \(a+b-9\); 否則可以變成 \(0\) 和 \(a+b\)。
那麼我們只要對這不是 \(0, 3, 6, 9\) 的那些位置進行特殊處理即可。為了方便,我們把這些位放在同一個數上。可以對於這些數提前統計他們的價值。然後對於剩下 \(k-1\) 個數,按照前面所提到的錯誤做法,對於第 \(x\)
\(\texttt{Code}\)
#include<bits/stdc++.h> using namespace std; #define L(i, j, k) for(int i = (j); i <= (k); i++) #define R(i, j, k) for(int i = (j); i >= (k); i--) #define ll long long const int N = 1e6 + 7; int n, m, k, sz, t, q; ll p[6], f[N]; void Push(int v, ll w) { R(i, 1e6, v) f[i] = max(f[i], w + f[i - v]); } void gg(int v, int w) { int now = min(k, (int)1e6 / v); for(int i = 1; i < now; i <<= 1) now -= i, Push(v * i, 1ll * w * i); Push(v * now, 1ll * w * now); } int main() { scanf("%d", &k), sz = 1, k = 3 * (k - 1); L(i, 0, 5) scanf("%d", &p[i]); L(i, 0, 1e6) { int now = 0, x = i, s = x % 10; while(x) { if(s % 3 == 0) f[i] += 1ll * p[now] * (s / 3); x /= 10, ++now, s = x % 10; } } L(i, 0, 5) gg(sz * 3, p[i]), sz *= 10; scanf("%d", &q); while(q--) scanf("%d", &t), printf("%lld\n", f[t]); return 0; }