[2020 NOI Online 入门组]跑步(民间数据)
思路:
这题其实就是一个背包的模板,但是他也有一个难点:他的数据太大了……
测试点编号 | n ≤ n \leq n≤ | 测试点编号 | n ≤ n \leq n≤ |
---|---|---|---|
1 1 1 | 5 5 5 | 6 6 6 | 2000 2000 2000 |
2 2 2 | 10 10 10 | 7 7 7 | 5000 5000 5000 |
3 3 3 | 50 50 50 | 8 8 8 | 20000 20000 20000 |
4 4 4 | 100 100 100 | 9 9 9 | 50000 50000 50000 |
5 5 5 | 500 500 500 | 10 10 10 | 100000 100000 100000 |
我们的背包DP在测试点8的时候还能应付,但是到了测试点9和测试点10的时候就会超时
f[j] = (f[j - i] + f[j]) % p;
然后我们就
没办法了,等S吧还有一个办法,他就是……
整数的无序分拆!
整♪数♪的♪无♪序♪分♪拆,我♪的♪救♪星♪
首先我们先定义状态:
设 f ( n , k ) f(n,k) f(n,k)为 n n n拆成 k k k个正整数部分有 f ( n , k ) f(n,k) f(n,k)种方案( k k k由小到大排列)
f ( n , k ) f(n,k) f(n,k)根据最后一部分是否大于1,分成两种情况
f ( n , k ) = { f ( n − 1 , k − 1 ) A k = 1 f ( n − k , k ) A k > 1 f(n,k)=\begin{cases}f(n-1,k-1) \quad \quad A_k = 1 \\f(n - k, k) \quad \quad \quad A_k > 1\end{cases} f(n,k)={f(n−1,k−1)Ak=1f(n−k,k)Ak>1
∴ f ( n , k ) = f ( n − 1 , k − 1 ) + f ( n − k , k ) ∴f(n,k)=f(n-1,k-1)+f(n-k,k) ∴f(n,k)=f(n−1,k−1)+f(n−k,k)
我们接着将我们敬爱的小H的跑步的速度x分为两类来做
-
x ≤ n x \leq \sqrt n x≤n 时
f [ n ] = f [ n − x ] f[n]=f[n-x] f[n]=f[n−x]
那么我们 O ( n n ) O(n\sqrt n) O(nn) -
x > n x > \sqrt n x>n 时
g ( n , k ) = g ( n − 1 , k − 1 ) + g ( n − k , k ) k ≤ n g(n,k) = g(n-1,k-1)+g(n-k,k) \quad k \leq \sqrt n g(n,k)=g(n−1,k−1)+g(n−k,k)k≤n
那么我们的时间复杂度又是 O ( n n ) O(n\sqrt n) O(nn)我们就不会超时啦啦♪(∇*)
最终的递推式是这样的:
∑
i
=
1
i
<
=
n
(
f
[
i
]
∗
∑
k
=
1
k
<
n
g
(
n
−
i
,
k
)
)
\sum_{i=1}^{i<=n}(f[i] * \sum_{k=1}^{k< \sqrt n} g(n-i,k))
∑i=1i<=n(f[i]∗∑k=1k<ng(n−i,k))
思路到此结束,代码写不来如下
f[j]=(f[j-i]+f[j])%p;
g[0][0]=1;
g[i][1]=1;
g[i][j]=(g[i-j][j]+g[i-m][j-1])%p;
ans=(ans+1ll*f[i]*g[n-i][j])%p;
亲测AC~~~