递归基础
递归基础
给小朋友讲课,被这两题小卡了一下啊,真的是蒟蒻啊...
题目大意:
对一个数n(n<=1000)做以下操作:
1、不做处理
2、在左边加上一个数,该数字小于等于其右边的一半
3、加上数后继续第二步,直到加不了数为止
问能构造出多少这样的数字
思路:
以6为例子,6自己本身算一个;6可以分成16,26,36 ;26可以变成126 ;36可以变成136。就是说对于每一位数字x,我们需要知道1~x//2能构造多少种。于是有以下解法:
ll dfs(ll x){
if(x == 1) return 1 ;
ll res = 1 ;
for(int i = 1 ; i <= x / 2 ; i ++ )
res += dfs(i) ;//搜索 1~x/ 2有几种
return res ;
}
但是n会到1000,而我们对每一个数都会去搜索一遍,存在着大量的重复冗余操作。会导致时间复杂度爆炸。于是需要记忆化搜索。注意到以上代码,dfs(x)时,返回值是res,而做完搜索后res就直接丢掉了,下次如果还要搜索x就要再做一次。这就是导致冗余操作的原因。所以只要在做完搜索后把res存起来就不用多次搜索同一个值了。
ll dp[N] ;
ll dfs(ll x){
if(dp[x]) return dp[x] ;//搜索已经搜过的值时直接访问dp数组
dp[x] = 1 ;
for(int i = 1 ; i <= x / 2 ; i ++ )
dp[x] += dfs(i) ;//搜索1~x/2有几种
return dp[x] ;
}
<========================================================================>
题目大意:
给定一个正整数x,要将其分成x = a1*a2*a3...的形式并且a1~an非递减
思路:
遍历从2到根号x的所有因子然后向下搜索,注意非递减条件,所以要知道他前一个因子是多少,我们选择的下一个因子要大于等于他。
ll ans ;
void dfs(ll pre , ll x){//debug ;
for(int i = 2 ; i * i <= x ; i ++ ){
if(x % i == 0 && pre <= i){
ans ++ ;
dfs(i , x / i) ;
}
}
}
int main(){
ios::sync_with_stdio(false) ;
cin >> n ;
while(n -- ){
ll m ; ans = 0 ;
cin >> m ;
dfs(0 , m) ;
cout << ans + 1 << "\n" ;
}
}

浙公网安备 33010602011771号