记忆化搜索 P1028 数的计算

P1028 [NOIP2001 普及组] 数的计算 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

一开始是想暴力搜索的,也就是枚举比n/2小的数,但是只过了5个点,其他点都TLE

然后就开始想有没有优化方法

以6为例子

6/2=3,那么以6为首的长度为2的序列就有61,62,63,也就是所有小于等于3的数的个数

接下来,我们找长度为3的序列的个数,只需要关注第二位的数字即可, 也就是说只需要找到以1,2,3为首的序列的个数相加即可

至此可以知道N[6]=N[3]+N[2]+N[1]+1;同理,N[3]=N[1]+1,N[2]=N[1]+1,N[1]=1;

这里的加1指的是只有首元素的序列,由此我们可以得出N[k]=N[1]+N[2]+......+N[k/2]+1的递推公式,这样递推下去,知道推到初始值N[1]=1就可以得出答案了

同时防止重复计算某个位置的值,采用记忆化搜索策略,否则还是会TLE

AC代码

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 int cnt = 1;
 6 int dp[1010] = { 0 };
 7 int Solve(int n)
 8 {
 9     
10     if (dp[n] == 0)//当此位置为被计算过才进行计算后返回,否则直接返回
11     {
12         if (n == 1)
13         {
14             dp[n] = 1;
15             return dp[n];//边界返回
16         }
17         for (int i = 1; i <= n / 2; i++)
18         {
19             dp[n] += Solve(i);//累加
20         }
21         dp[n] += 1;
22     }
23     return dp[n];
24 }
25 int main()
26 {
27     int n;
28     cin >> n;
29     Solve(n);
30    cout << dp[n];
31 }

 

posted @ 2023-05-03 21:47  凪风sama  阅读(23)  评论(0编辑  收藏  举报