P6189 [NOI Online #1 入门组] 跑步 (DP/根号分治)
(才了解到根号分治这样的妙方法......)
将每个数当成一种物品,最终要凑成n,这就是一个完全背包问题,复杂度O(n2),可以得80分(在考场上貌似足够了......)
1 #include <bits/stdc++.h> 2 //#define loveGsy 3 #define N 1000005 4 using namespace std; 5 int f[N]; 6 7 int main() { 8 #ifdef loveGsy 9 freopen("a.in", "r", stdin); 10 freopen("a.out", "w", stdout); 11 #endif 12 int n, p; 13 cin >> n >> p; 14 f[0] = 1; 15 for (int i = 1; i <= n; i++) 16 for (int j = i; j <= n; j++) 17 f[j] = (f[j-i] + f[j]) % p; 18 cout << f[n] <<endl; 19 return 0; 20 }
接着采用根号分治,将1~n这些数由sqrt(n)分成两半,前一半还是用完全背包的做法,复杂度O(n*sqrt(n)),再考虑另一种DP,gi,j表示从sqrt(n)~n之间选i个数,它们的和为j。
转移方程是g[i][j]=g[i][j-i]+g[i-1][j-m]。其中m就是sqrt(n)。g[i][j-i]可以理解为给数集中的每个数都加上1,g[i-1][j-m]理解为在数集中加入m这个数。两种DP统计完之后合并就行了(乘法原理),前一个为i,后一个就是n-i。
那么第二种DP为什么可以用呢?,因为从m~n之间选的数的个数一定不超过m,复杂度也就是O(n*sqrt(n))。
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 const int N = 1e5 + 10; 5 6 int n, p, m; ll ans = 0; 7 int f[N], g[410][N]; 8 9 signed main() { 10 cin >> n >> p; 11 m = sqrt(n) + 1; 12 f[0] = 1; 13 for (int i = 1; i < m; i++) 14 for (int j = i; j <= n; j++) 15 f[j] = (f[j] + f[j - i]) % p; 16 g[0][0] = 1; 17 for (int i = 1; i < m; i++) 18 for (int j = i; j <= n; j++) { 19 g[i][j] = g[i][j - i]; 20 if (j >= m) g[i][j] = (g[i][j] + g[i - 1][j - m]) % p; 21 } 22 for (int i = 0; i <= n; i++) { 23 int sum = 0; 24 for (int j = 0; j < m; j++) sum = (sum + g[j][n - i]) % p; 25 ans = (ans + 1ll * f[i] * sum) % p; 26 } 27 cout << ans << endl; 28 return 0; 29 }
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!