记忆化搜索 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 }