Codeforces 1487F Ones

rizynvu發表於2024-04-15

考慮令 \(l = |n|\),最高位為第 \(1\) 位,最低位為第 \(l\) 位。

考慮選了一個 \(\pm\underbrace{11\cdots11}_{i}\),那麼顯然會對 \(l - i + 1\sim l\) 位都有影響。
於是能夠知道第 \(i\) 位只有可能由 \(< i\) 的位影響。

便可以考慮由高位到低位依次考慮,假設到了第 \(i\) 位。
首先需要考慮 \(\le i\) 的位已經給第 \(i\) 位加了多少了。
同時考慮到 \(< i\) 的位可能給第 \(i\) 位留下了一些空去補。
同時考慮記錄一下第 \(i\) 位選擇 \(+ 1\) 還是 \(- 1\),顯然不會又有 \(+1\) 又有 \(-1\)

所以可以設 \(f_{i, x, c, \Delta}\) 分別代表上面的量對應的值所需要的最小花費。
考慮會有 \(2\) 種選擇:

  1. \(i\)\(+ \Delta\),花費 \(1\),直接在 \(x\) 的部分 \(+ \Delta\) 即可。
    \(f_{i, x + \Delta, c, \Delta} + l - i + 1\to f_{i, x, c, \Delta}\)
  2. 推到第 \(i + 1\) 位,那麼第 \(i + 1\) 位就可能是 \(1\)\(-1\),同時可以更新 \(c\),相當於前面的差值後面添上了這位的差值,就是 \(10c + s_i - \Delta\)
    \(\min\{f_{i + 1, x, 10c + s_i - x, -1 / 1}\}\to f_{i, x, c, \Delta}\)

邊界條件就是當 \(i = l\) 的時候,要求到 \(i + 1\) 的時候 \(c = 0\) 才是合法的,相當於就是要使 \(10c + s_l - x' = 0\)\(|x - x'|\) 的這個值,所以有 \(f_{l, x, c, ?} = |10c + s_l - x|\)

但這個 \(c, x\) 的範圍都會很大,但是考慮到大部分狀態都是沒用的,考慮減掉這部分狀態。

首先考慮 \(x\)
考慮到 \(\underbrace{77\cdots77}_{i} = \underbrace{11\cdots11}_{i + 1} - \underbrace{33\cdots3}_i - 1\),先把這個 \(-1\) 考慮到第 \(l\) 位已經特殊處理了,那麼就可以知道實際上對於第 \(i\) 位來說不會操作 \(> 6\) 次。
那麼一共有 \(l\) 位,操作次數就會 \(\le 6l\),於是有 \(x\le 6l\)

再考慮 \(c\),考慮若 \(c \ge 0\),最後 \(c\) 肯定還是要滿足最小值 \(\le 0\) 才有可能為 \(0\)
考慮對於第 \(l\) 位的 \(c\),那肯定有 \(10c - x\le 0\)
繼續,有 \(10(10c - x) - x\le 0\),到了最後會成這樣:\(c\le \dfrac{\underbrace{11\cdots11}_{l} x}{10^l}\)
卡一個寬鬆的上界,肯定有 \(c\le \frac{x}{5}\)

然後直接 \(\text{DP}\) 就行了。

時間複雜度 \(O(n^3)\)

程式碼
#include<bits/stdc++.h>
const int inf = 0x3f3f3f3f;
const int maxl = 50 + 2, maxx = maxl * 6, maxc = maxx / 5;
char S[maxl];
int s[maxl];
int l, mxx, mxc;
int f[maxl][maxx << 1][maxc << 1][3];
int dfs(int w, int x, int c, int v) {
   if (w == l)
      return abs((c * 10 + s[w]) - x);
   if (x < -mxx || x > mxx || c < -mxc || c > mxc)
      return inf;
   int &ans = f[w][mxx + x][mxc + c][v + 1];
   if (ans == -1)
      ans = std::min({dfs(w, x + v, c, v) + l - w + 1, 
                      dfs(w + 1, x, c * 10 + s[w] - x, 1),
                      dfs(w + 1, x, c * 10 + s[w] - x, -1)});
   return ans;
}
int main() {
   scanf("%s", S + 1);
   l = strlen(S + 1);
   for (int i = 1; i <= l; i++)
      s[i] = S[i] - '0';
   mxx = l * 6, mxc = mxx / 5;
   memset(f, -1, sizeof(f));
   printf("%d\n", dfs(0, 0, 0, 1));
   return 0;
}

相關文章