考慮一個不斷成長的數列:第 $1$ 回合的數列是 $S_1=[1]$,第 $n$ 回合做的事情是先把 $n$ 放進去再把剛才的數列照抄一次:$S_n = [S_{n-1}, n, S_{n-1}]$ 給你 $n$ 以及 $k$,請問第 $n$ 個數列的第 $k$ 項是多少?

不難發現前幾項是 $1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, \ldots$,所以答案就會是 $k$ 寫成二進位以後末尾 $0$ 的數量加一。實作上可以用 __builtin_ctzll() 來處理,要記得加上 ll 以免向隅。

// by tmt514
int main(void) {
  long long n, k;
  cin >> n >> k;
  cout << 1 + __builtin_ctzll(k) << endl;
  return 0;
}

有一天你寫了一個數字在黑板上,印象中你記得所有數字的總和 $\ge k$。當你離開座位一陣子了以後,卻發現你數字某些位數被擦掉改寫成 $n$ 了。請問無論如何,至少有幾個數字被擦掉了呢?$n\le 10^{100000}$、$k\le 10^9$。題目保證有解。

這題是 Greedy,你可以直接把所有 digit 排序,然後從最小的開始,依次把他改成 9,直到總和超過 $k$ 為止。

// by tmt514
int main(void) {
  int k, ans = 0;
  string n;
  cin >> k >> n;
  sort(n.begin(), n.end());
  for(auto &&x: n) k -= x-'0';
  for(auto &&x: n) if(k>0) { k -= '9'-x; ++ans; }
  cout << ans << endl;
  return 0;
}

Memory 想要從平面座標上的原點,經過一連串的指令以後回到原點。這串指令可以寫成一個字串 $s$,並且包含 L, R, U, D 四種字元分別代表向左、向右、向上、向下各走一單位距離。為了讓 Memory 能夠順利回到原點,請問至少要修改這個字串的幾個字元呢?如果無論如何都無法達成目標,請輸出 $-1$。$1\le |s|\le 10^5$。

首先我們可以知道,若字串長度是奇數鐵定無解。接著我們可以透過計算 LR 的數量、計算 UD 的數量來決定要修改幾個字元。

// by tmt514
int main(void) {
  string s;
  int LR=0, UD=0;
  cin >> s;
  for(auto &&x: s) {
    if(x=='L' || x=='R') LR += (x=='L'?1:-1);
    if(x=='U' || x=='D') UD += (x=='U'?1:-1);
  }
  LR = abs(LR);
  UD = abs(UD);
  if((LR+UD)%2) cout << -1 << endl;
  else cout << (LR+UD)/2 << endl; 
  return 0;
}

Vasiliy 在一間療養院度過了他的假期,回來的時候幾乎忘了所有的細節了!

在療養院美一天都有早餐(breakfast)、晚餐(dinner) 以及宵夜(supper)。Vasiliy 只記得他吃過了 $b$ 餐早餐、$d$ 餐晚餐以及 $s$ 餐宵夜,但是他不記得他是在一天之中的什麼時候抵達、一天之中的什麼時候離開的。

現在給你 $b, d, s$ 的值,請問他在療養院的時候,至少錯過了幾餐? ($0\le b, d, s\le 10^{18}$, $b+d+s\ge 1$)

本題有趣的地方在於,若 Vasiliy 沒有錯過任何一餐,那麼其敘述等價於 $\max(b, d, s) - \min(b, d, s) = 1$。所以只要找出三個數字最大的值,然後把其他兩個補足到至少該值減 $1$ 即可。

// by tmt514
int main(void) {
  long long b, d, s;
  cin >> b >> d >> s;
  long long x = max(b, max(d, s));
  long long c = max(0LL, (x-1)-b);
  c += max(0LL, (x-1)-d);
  c += max(0LL, (x-1)-s);
  cout << c << endl;
  return 0;
}