题解 CF414B 【Mashmokh and ACM】

rui_er

2020-09-02 18:51:31

Solution

一道小清新动规题。 题意:求长度为 $k$ 的、最大数不超过 $n$ 的数列,满足 $a_i=a_{i-1}\times mul$($2\le i\le n$ 且 $mul$ 为正整数)。 --- 思路: 容易想到设计状态 $dp_{i,j}$ 表示长度为 $i$ 时最大数为 $j$ 的方案总数。 转移方程也比较好想,根据数列要求,枚举所有可能的倍数,加上对应方案的 $dp$ 值即可。即:$dp_{i,j}=\displaystyle\sum_{k\ \text{是}\ j\ \text{的因数}}dp_{i-1,k}$。由于因数不好统计,我们根据 $i,k$ 来反推即可。 但是还没有结束,虽然我们可以通过此题,但是作为一个优(du)秀(liu)的 OIer,你不觉得 $dp$ 数组这么大很多余吗?我们对于每一个 $i$,只用到了 $i-1$ 的 $dp$ 值,显然可以压缩空间啊! 考虑将 $dp_j$ 定义为最大数为 $j$ 的方案总数,原本的 $i$ 是没有必要存的。转移方程也没有特别大的变化。 --- 代码: ```cpp //By: Luogu@rui_er(122461) #include <bits/stdc++.h> using namespace std; typedef long long ll; const ll N = 2005, mod = 1e9+7; ll n, k; ll dp[N], tmp[N], ans; int main() { scanf("%lld%lld", &n, &k); for(ll i=1;i<=n;i++) dp[i] = 1; for(ll cnts=2;cnts<=k;cnts++) { for(ll i=1;i<=n;i++) tmp[i] = 0; for(ll i=1;i<=n;i++) { for(ll j=1,_=i*j;_<=n;j++,_=i*j) tmp[_] = (tmp[_] + dp[i]) % mod; } for(ll i=1;i<=n;i++) dp[i] = tmp[i]; } for(ll i=1;i<=n;i++) ans = (ans + dp[i]) % mod; printf("%lld\n", ans); return 0; } ```