USACO2024DEC铜组T1

USACO铜组T1

首先,我们先看 \(99\) 中会约错的数字
显然有 \(45\) ~ \(49\)\(5\)

然后,我们再看 \(100\) ~ \(999\) 中会约错的数字
显然有 \(445\) ~ \(499\)\(55\)

然后,我们再看 \(1000\) ~ \(10000\) 个中会约错的数字
显然有 \(4445\) ~ \(4999\)\(555\)

由此,我们可以得出结论:在 \(10^n\) ~ \(10^{n + 1} - 1(n \ge 1)\) 中,总共有 \(\displaystyle\sum^{n}_{i=1}(5*10^{i - 1})\) 个数字会被约错,而在 \(2\) ~ \(9\) 中没有数字会被约错

不严谨的证明:
\(1000\) ~ \(9999\) 来说
如果某一个数小于 \(4445\),那么无论是四舍五入还是链式舍入,显然都会约到 \(0\)
而如果一个数大于 \(4999\),那么这两种舍入的方式都会约到 \(10000\)


于是,我们可以对于给定的 \(n\),先找到一个最大的整数 \(k\),使得 \(10^k-1\le n\),然后统计 \(2\) ~ \(10^k-1\) 中的所有 \(10^i\) ~ \(10^{i + 1} - 1\) 的答案个数相加
然后,再判断一下 \(n\) 是否在 \(10^k\) ~ \(10^{k+1}-1\) 中可能出现约错的区间内:如果小于,则答案不用再做处理;如果在区间内,则答案加上部分会约错的数;如果大于,则答案加上全部会约错的数

点击查看代码
#include <iostream>
#include <cmath>
#define int long long

using namespace std;
const int maxn = 15;

long long ge[maxn];

signed main()
{
  ge[0] = 0;
  ge[1] = 0;
  for (int i = 2; i <= 9; ++i)
  {
    for (int j = 1; j <= i - 1; ++j)
    {
      ge[i] = ge[i] * 10 + 5;
    }
  }
  // 统计每一个10^i~10^{i+1}-1区间的答案个数
  int t;
  cin >> t;
  while (t--)
  {
    int n;
    cin >> n;
    if (n <= 10)
    {
      cout << 0 << '\n';
      continue;
    }
	//这里直接特判
    int d = n;
    int cnt = 0;
    while (d)
    {
      ++cnt;
      d /= 10;
    }
    cnt--;
    int ans = 0;
    for (int i = 1; i <= cnt; ++i)
    {
      ans += ge[i];
    }
	// 统计所有出现的区间的答案总和
    int m = 0;
    for (int i = 1; i <= cnt; ++i)
    {
      m = m * 10 + 4;
    }
    m = m * 10 + 5;
    if (n >= m && n < 5 * pow(10, cnt))
    {
      ans += n - m + 1;
    }
    else if (n >= 5 * pow(10, cnt))
    {
      ans += ge[cnt + 1];
    }
	// 判断是否在可能约错的区间之下/之中/之上
    cout << ans << '\n';
  }

  return 0;
}
posted @ 2024-12-16 21:41  SigmaToT  阅读(57)  评论(0)    收藏  举报