2 条题解

  • 0
    @ 2026-6-12 19:54:02

    官方题解在干什么啊???

    首先注意到一个数如果位数能更小,取更小总是更优的。

    那么具体能多小呢?

    首先,显然如果 aa 的位数 >b>b 的位数,则有 a>ba>b。设 wiw_i 为 aia_i 的位数,则显然有 wi≤wi+1w_i\le w_{i+1}。

    紧接着,考虑到如果位数是相同的,则 a,ba,b 的大小关系和它们的字典序大小关系一致。于是如果有 pi>pi+1p_i>p_{i+1},则有 wi+1=wi+1w_i+1=w_{i+1}。

    求出 wiw_i 后,直接按找字典序贪心地取最小字典序即可。正确性显然:

    • 依据 wiw_i 的构造,可以保证 ai<ai+1a_i<a_{i+1};
    • 由于单个数时 wiw_i 相同,故字典序最小时就是最小的。

    那么如何取最小字典序?这一个数的 ww 比前面的大,那么直接补 00 即可;否则,需要在最后一位上 +1+1。前面的位都不用变。

    可以直接单调栈维护,时间复杂度 O(n)O(n),把 std 的四毛子 O(n)O(n) 按在地上摩擦。

    • 0
      @ 2026-6-11 21:01:26

      进制数 1018−3910^{18} - 39 实在是太大了,因此位数多了就一定不是最优的,考虑确定每个数的位数:

      • ai+1a_{i + 1} 的位数不少于 aia_i。
      • 若 pi>pjp_i > p_j 且 i<ji < j,则 apia_{p_i} 的位数一定严格多于 apja_{p_j}。

      由以上两条结论可以计算每个数的最少位数,并且可以证明最优解一定都取这样算出来的位数:假设 aia_i 是第一个不取算出来的位数的数字,由于 ai+1a_{i + 1} 的位数与 aia_i 的位数的差值的最小值也是确定的(若排列 pp 中 i+1i + 1 排在 ii 前面则为 11,否则为 00),而原方案全部取到了最小差值,因此最后 ana_n 的位数一定大于原方案的位数,因此不是最优的。

      接下来为每个数的每一位填写数字:设当前正在填写字典序排序的序列中 [l,r][l, r] 位置内第 tt 高位及以后的值,则其中的 tt 位数至少依次填写为 0,1,…0, 1, \ldots(如果 apla_{p_l} 不是 tt 位数,起点要加上 11;如果 t=1t = 1,起点也要加上 11;如果都有,起点要加上 22),且 apl,apl+1,…,apra_{p_l}, a_{p_{l + 1}}, \ldots, a_{p_r} 的这一位必须单调不降。填完之后,只需要对其中每个第 tt 位相同的区间递归处理子区间即可。

      在递归过程中对不存在 tt 位数的 tt 直接跳过,最终的时间复杂度为 O(nlog⁡n)O(n \log n),空间复杂度为 O(n)O(n)(如果使用线段树实现 RMQ),瓶颈在跳过不合法 tt 使用的 RMQ。

      (实际上,我们也可以套用 O(n)−O(1)O(n)-O(1) RMQ 把时间复杂度降到 O(n)O(n),但是意义不大。)

      #include <bits/stdc++.h>
      using namespace std;
      const int N = 1e5 + 12, M = 17, B = 10, P = 1e9 + 7;
      int p[N], q[N], d[N], b[N], w[N];
      long long s[N][M];
      pair <int, int> dfs(int l, int r, int n, int c, int e)
      {
      	if (l > r) return make_pair(0, 0);
      	if (l == r) return make_pair((int) (1ll * e * b[d[p[l]] - c] % P), b[d[p[l]] - c]);
      	long long u = 0, v = 0;
      	int z = w[r - l + 1], t = min(s[l][z], s[r - (1 << z) + 1][z]) / n;
      	if (d[p[l]] == t)
      	{
      		u = e;
      		v = b[t - c];
      		l++;
      	}
      	while (l <= r)
      	{
      		int z = w[r - l + 1];
      		long long y = min(s[l][z], s[r - (1 << z) + 1][z]);
      		if (y / n != t) break;
      		pair <int, int> x = dfs(l, y % n, n, t + 1, 0);
      		u = (u + x.first + 1ll * e * (1ll * B * x.second % P + 1) + 1) % P;
      		v = (v + 1ll * b[t - c] * (1ll * B * x.second % P + 1)) % P;
      		l = y % n + 2;
      		e++;
      	}
      	pair <int, int> x = dfs(l, r, n, t + 1, 0);
      	u = (u + x.first + 1ll * e * B % P * x.second % P) % P;
      	v = (v + 1ll * b[t - c] * B % P * x.second % P) % P;
      	return make_pair(u, v);
      }
      int main()
      {
      	freopen("seminar.in", "r", stdin);
      	freopen("seminar.out", "w", stdout);
      	int n;
      	cin >> n;
      	for (int i = 0, j = 1; j <= n; i++, j <<= 1)
      		w[j] = i;
      	for (int i = 3; i <= n; i++)
      		if (!w[i]) w[i] = w[i - 1];
      	b[0] = 1;
      	for (int i = 1; i <= n; i++)
      		b[i] = 1ll * b[i - 1] * B % P;
      	for (int i = 1; i <= n; i++)
      		cin >> p[i];
      	for (int i = 1; i <= n; i++)
      		q[p[i]] = i;
      	d[1] = 1;
      	for (int i = 2; i <= n; i++)
      	{
      		d[i] = d[i - 1];
      		if (q[i] < q[i - 1]) d[i]++;
      	}
      	for (int i = 1; i <= n; i++)
      		s[i][0] = 1ll * d[p[i]] * n + i - 1;
      	for (int j = 1; (1 << j) <= n; j++)
      		for (int i = 1; i + (1 << j) - 1 <= n; i++)
      			s[i][j] = min(s[i][j - 1], s[i + (1 << (j - 1))][j - 1]);
      	cout << dfs(1, n, n, 1, 1).first << endl;
      	return 0;
      }
      
      • 1

      [Sleeping Cup #11] Interstellar JavaScript Seminar

      信息

      ID
      273
      时间
      1000ms
      内存
      512MiB
      难度
      7
      标签
      递交数
      8
      已通过
      3
      上传者