agc011_e 题解

一种 luogu 题解区没有的新做法。

考虑一个非常有道理的贪心:假设当前的数是 \(n\),每次选择 \(\le n\) 的最大的递增数 \(v\) ,将 \(n\) 变为 \(n-v\)。

考虑上面的加粗部分比较抽象,实际上,比如样例 \(n=20170312\),那么 \(v=19999999\)。

感性理解就是一定会让最高位没掉。

但是直接做是 \(\mathcal{O}(n^2)\) 的,考虑优化,如果使用线段树来维护高精度可以做到 \(\mathcal{O}(n\log n)\)。

考虑继续优化,发现瓶颈在于每次减去形如 \(\overline{a}99\dots9\),则相当于先加减去一个 \(\overline{a}\times(10^k+1)\),再加 \(1\)。发现前者会刚好消去当前这个数前若干位,而后者均摊是 \(\mathcal{O}(n)\) 的,因此可以优化到 \(\mathcal{O}(n)\)。

代码:

cpp 复制代码
vector<int> num;
string str; cin >> str;
for (char c : str) num.pb(c - '0');
int step = 0, pos = -1, cur = 0;
while (true) {
  ++step;
  if (pos < cur) {
    for (int i = cur; i + 1 < num.size(); ++i) if (num[i] > num[i + 1]) {
      pos = i;
      break;
    }
    if (pos < cur) break;
  }
  int sep = num[pos];
  while (true) {
    int f = num[cur];
    ++cur;
    if (f == sep) break;
  }
  [&]{
    for (int i = (int)num.size() - 1; i >= cur; --i) {
      if (num[i] < 9) {
        ++num[i];
        if (i <= pos + 1) pos = cur - 1;
        return;
      }
      num[i] = 0;
    }
    --cur;
    num[cur] = 1;
    pos = cur - 1;
  }();
  while (num[cur] == 0) ++cur;
}
cout << step << "\n";
相关推荐
Matrix_119 分钟前
手机里的计算摄影:广角形变校正算法
人工智能·算法·智能手机·计算摄影
WBluuue14 分钟前
数据结构与算法:有序表(二):跳表
数据结构·c++·算法·skiplist
x138702859571 小时前
c语言中srtlen(指针使用计算字符长度)、传值和传址调用
c语言·开发语言·算法·visual studio
海兰2 小时前
【实用程序】电商销售分析仪表盘 — 从零搭建一个AI参与的全栈数据洞察系统
人工智能·学习·算法
zwenqiyu2 小时前
P5283 [十二省联考 2019] 异或粽子题解
c++·学习·算法
wayz112 小时前
Momentum:TSI(真实强度指数)技术指标详解
算法·金融·数据分析·量化交易·特征工程
万事大吉CC3 小时前
Python 笔试输入模板总结
python·算法
lihao lihao3 小时前
Linux信号
开发语言·c++·算法
大白话_NOI3 小时前
【洛谷 P2249】查找(深基 13. 例 1)+ 详细分析
c++·算法
吠品3 小时前
C++实现m行n列带边框的长方形输出
算法