考虑 DP。

状态

令 $f[\ell][x]$ 表示长度为 $\ell$,首项不超过 $x$ 的序列的个数。

答案是 $f[K][N]$。

有递推 $f[\ell][x] = f[\ell][x - 1] + f[\ell - 1][\floor{N/x}]$。照这个递推式求解,复杂度度太高;把它改成

$f[\ell][x] = \sum_{y = 1}^{x} f[\ell - 1][\floor{N/y}]$ 也就是枚举首项。

我们的目标是求出 $f[K][N]$,结合递推式来看,可以发现我们需要计算的状态的第二维都可以写成 $\floor{N/i}$。而我们熟知 $\floor{N/i}$ 的不同取值不超过 $2 \sqrt{N}$ 个。因此需要计算的状态不超过 $2K\sqrt{N}$ 个。

先来解决状态表示的问题,也就是 $\floor{N/i}$ 的表示问题。虽然 $\floor{N/i}$ 的取值不超过 $2\sqrt{N}$ 个,但是不能直接以 $\floor{N/i}$ 作为数组下标。可以这样做,对于 $\color{blue}{ i \le \sqrt{N} }$,用 $i$ 表示 $\floor{N/i}$,对于 $\color{red}{ i \ge \sqrt{N} }$,直接以 $\floor{N/i}$ 作为下标。从代码实现的角度说就是开两个数组,$f_1[1..K][1..\floor{\sqrt N}],\ f_2[1..K][1..\floor{\sqrt N}]$,$f_1[\ell][i] := f[\ell][i]$,$f_2[\ell][i] := f[\ell][\floor{N/i}]$。

注①:当 $N$ 是完全平方数时,$i \le \sqrt N$ 与 $i \ge \sqrt N$ 这两段中都含有 $\sqrt{N}$,这并不会造成问题。实际上分段时两侧都取等号是有意为之,这样可以使得递推式更简洁并且没有 corner case。这种分段方法适用于许多跟 $\floor{N/i}$ 相关的分块问题。

注②:关于上一段所说的“对于 $i \le \sqrt N$,用 $i$ 表示 $\floor{N/i}$”,我们不需要关心 $i \mapsto \floor{N/i}$ 是不是单射。这里所谓“表示 $\floor{N/i}$”是说设计一种方法来把所有需要计算的 $f[\ell][\floor{N/i}]$ 紧凑地存到数组里并且可以快速地由 $\ell, i$ 这两个 key 查到 $f[\ell][\floor{N/i}]$ 的值。不过可以证明,对于 $i \le \sqrt{N}$,$i \mapsto \floor{N/i}$ 确实是单射。

递推

对于 $f_1$,有递推

$f_1[l][x] = f_1[l][x - 1] + f[l - 1][\floor{N/x}]$

由于 $1 \le x \le \floor{\sqrt{N}}$,有 $f[l - 1][\floor{N/x}] = f_2[l-1][x]$,从而有

$f_1[l][x] = f_1[l][x - 1] + f_2[l-1][x]$

对于 $f_2$,有递推式

$f_2[l][i] = f_2[l][i+1] + \sum_{x=\floor{N/(i+1)} + 1}^{\floor{N/i}} f[l -1][\floor{N/x}] $

容易证明下列几个不等式

  1. $\floor{N/i} \ge \floor{N/(i + 1)}$
  2. $\floor{N/\floor{N/i}} \ge i$
  3. $\floor{N / \left(\floor{N/i} + 1 \right) } < i$

只证第 3 个。

设 $ \floor{\frac{N}{i}} = t$,我们有

$ t \le \frac{N}{i} < t + 1 \iff it \le N < i(t + 1) \iff i\frac{t}{t + 1} \le \frac{N}{t + 1} < i \implies \floor{\frac{N}{t + 1}} < i$

因此我们有 $i \le \floor{\frac{N}{x}} < i + 1$,即对于 $\floor{\frac{N}{i + 1}} < x \le \floor{\frac Ni}$ 恒有 $ \floor{\frac{N}{x}} = i $,这里我们得到一个很有用的等式

若 $\floor{\frac{N}{i}} \ge \floor{\frac{N}{i+1}}$,则

$f[l][\floor{\frac{N}{i}}] = f[l][\floor{N/(i + 1)}] + \left( \floor{\frac{N}{i}} - \floor{\frac{N}{i+1}} \right) f[l - 1][i] $

并且当 $\floor{\frac{N}{i}} > \floor{\frac{N}{i+1}}$ 时,$i$ 可表为 $\floor{ \frac{N}{ \floor{ \frac{N}{i} } } }$

从而有

\begin{aligned}

f_2[l][i] &= f_2[l][i+1] + \left( \floor{\frac{N}{i}} - \floor{\frac{N}{i+1}} \right) f[l - 1][i] \\

&= f_2[l][i+1] + \left( \floor{\frac{N}{i}} - \floor{\frac{N}{i+1}} \right) f_1[l - 1][i]

\end{aligned}

$f_2$ 的边界条件有两个:

1.

$f_2[1][i] = \floor{ \frac{N}{i} } $

2.

\begin{aligned} f_2[l][\floor{\sqrt{N}}] &:= f[l][\floor{\frac{N}{\floor{\sqrt N}}}] \\

&= f[l][\floor{\frac{N}{\floor{\sqrt N}+1}}] + \left( \floor{ \frac{N}{ \floor{\sqrt{N}} } } - \floor{ \frac{N}{\floor{\sqrt N}+1} } \right) f[l - 1][\floor{ \sqrt{N} } ] \\

&= f_1[l][\floor{\frac{N}{\floor{\sqrt N}+1}}] + \left(\floor{\frac{N}{\floor{\sqrt{N}}}} - \floor{\frac{N}{\floor{\sqrt{N}} + 1}} \right) f_1[l - 1][\floor{ \sqrt{N} } ]

\end{aligned}

代码

int main() {

    int n, k;
scan(n, k);
int r = sqrt(n + 0.5); // r is defined to be floor(sqrt{n})
vv<int> f1(k + 1, vi(r + 1)); // f1[len][i]:长为len,首项 <= i
vv<int> f2(k + 1, vi(r + 1)); // f2[len][i]:长为len,首项 <= n/i up (i, 1, r) {
f1[1][i]=i;
}
up (i, 1, r) {
f2[1][i] = n / i;
}
up (l, 2, k) {
up (i, 1, r) {
f1[l][i] = f1[l][i - 1] + f2[l - 1][i];
if (f1[l][i] >= mod) {
f1[l][i] -= mod;
}
}
f2[l][r] = f1[l][n/(r + 1)] + (ll)(n / r - (n / (r + 1))) * f1[l - 1][r] % mod;
if (f2[l][r] >= mod) {
f2[l][r] -= mod;
}
down (i, r - 1, 1) {
f2[l][i] = f2[l][i + 1] + (ll)(n / i - (n / (i + 1))) * f1[l - 1][i] % mod;
if (f2[l][i] >= mod) {
f2[l][i] -= mod;
}
}
}
println(f2[k][1]); return 0;
}

从另一个角度看待这个问题。以下所有 / 运算都向下取整。

取一个数字 m,求出 f[L][1..m]

f[L][i] = f[L][i-1] + f[L-1][N/i]

开一个数组 g[1..m],g[L][i] := f[L][N/i]

问题归结为如何计算 g[L][i]

上面已经得到

g[L][i] = g[L][i+1] + (L/i - L/(i+1))*f[L-1][i]

整个计算过程如下

for i = 1 to m

f[1][i] = i

g[1][i] = N/i

for L = 1 to K

f[L][0] = 0

for L = 2 to K

for i = 1 to m

f[L][i] = f[L][i-1] + g[L-1][i]

// compute g[L][m]

for i = m - 1 down to 1

g[L][i] = g[L][i+1] + (L/i - L/(i+1)) * f[L-1][i]

问题进一步归结为如何计算 g[L][m],即 f[L][N/m]

若 N/m <= m 则 f[L][N/m] 已经算出来了,不成问题。

若 N/m > m 但 N/(m + 1) <= m 则 f[L][N/m] = f[L][N/(m+1)] + (N/m - (N/(m+1))*f[L-1][m],也不成问题。

所以保险的办法是取 m 使得 N/(m + 1) <= m,取 m = floor(sqrt(N)) 就可以保证 N/(m+1) <= m。证明:m+1 > sqrt(N) 因此 N/(m+1) < sqrt(n) <= m 。

取 m = floor(sqrt(N)) + 1 可以保证 N / m < m。证明 m > sqrt(N),所以 N / m < sqrt(N) <= floor(sqrt(N)) < m。

ABC133F Small Products的更多相关文章

  1. Building third-party products of OpenCascade

    Building third-party products of OpenCascade eryar@163.com Available distributives of third-party pr ...

  2. SharePoint Configuration Wizard - Unable to upgrade SharePoint Products and Technologies because an upgrade is already in progress

    故障描述 当要运行SharePonit Products and Technologies Configuration Wizard的时候,出现了如下图所示的错误提示. 错误信息为: Unable t ...

  3. Registry values for ProductID and LocaleID for AutoCAD and the vertical products

    原文地址:http://adndevblog.typepad.com/autocad/2013/08/registry-values-for-productid-and-localeid-for-au ...

  4. magento添加多个产品到购物车(Add multiple products to cart )

    Step  1app\design\frontend\base\default\template\catalog\product\list.phtml<?php    $_productColl ...

  5. FVDI Commander products be replaced SVDI tools,really?

    You may have heard that some FVDI Commander products are being replaced by the new SVDI tools. This ...

  6. 读书笔记-《Training Products of Experts by Minimizing Contrastive Divergence》

    Training Products of Experts by Minimizing Contrastive Divergence(以下简称 PoE)是 DBN 和深度学习理论的 肇始之篇,最近在爬梳 ...

  7. /users/products.:format 这种写法的其对应解析字符写法

    “products.:format" 这种写法可以有对应的下面两种路由形式 /products.json /products.xml "products.:format?" ...

  8. Amazon.com: NEW VI AND VIM EDITOR KEYBOARD STICKER: Office Products

    Amazon.com: NEW VI AND VIM EDITOR KEYBOARD STICKER: Office Products NEW VI AND VIM EDITOR KEYBOARD S ...

  9. Popular Products

    Popular Products 描述 Given N lists of customer purchase, your task is to find the products that appea ...

随机推荐

  1. head命令:显示文件开头内容

    head 命令可以显示指定文件前若干行的文件内容,其基本格式如下:head [选项] 文件名 选项: 选项 含义 -n K 这里的 K 表示行数,该选项用来显示文件前 K 行的内容:如果使用 &quo ...

  2. vue子组件改变父组件的值

    1 在父组件的coment绑定事件 <template> <div :class="classObj" class="app-wrapper" ...

  3. [CSP-S模拟测试]:循环依赖(拓扑)

    题目传送门(内部题148) 输入格式 每个测试点第一行为一个正整数$T$,表示该测试点内的数据组数. 接下来$T$组数据,每组数据第一行一个正整数$n$,表示有引用单元格进行计算的单元格数,接下来$n ...

  4. JAVA异常及其异常处理方式

    异常处理 异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的.比如说,你的代码少了一个分号,那么运行出来结果是提示是错误 java.lang.Error:如果你用Syste ...

  5. HTTP服务器(1)

    import socket def service_client(new_socket): """为这个客户端返回数据""" # 1. 接收 ...

  6. C++入门经典-例8.8-虚继承

    1:以前讲到从CBird类和CFish类派生子类CWaterBird时,在CWaterBird类中将存在两个CAnimal类的复制.那么如何在派生CWaterBird类时使其只存在一个CAnimal基 ...

  7. TCP输入 之 快速路径和慢速路径

    概述 快速路径:用于处理预期的,理想情况下的数据段,在这种情况下,不会对一些边缘情形进行检测,进而达到快速处理的目的: 慢速路径:用于处理那些非预期的,非理想情况下的数据段,即不满足快速路径的情况下数 ...

  8. 2 大O表示法

    1.大O表示法 表示程序的执行时间或占用空间随数据规模的增长趋势. 算法操作 时间复杂度 线性查找 O(n) 二分查找 O(logn) 无序数组插入 O(1) 无序数组删除 O(n) 有序数组插入 O ...

  9. .net 查壳工具

    请问大神.NET查壳工具都有哪些? 已知的有DotNet Id    除了这个还有别的吗?脱MAXTOCODE发现是双壳.脱掉第一层还有一层,DotNet Id检测没壳了,但是反编译还是加密状态. 用 ...

  10. String,int,Integer之间的转换

    public class Test{ public static void main(String[] args) { //int转换成Integer Integer in = new Integer ...