前几个月放映的头号玩家简直火得不能再火了,作为一个探索终极AI的研究人员,月神自然去看了此神剧。
由于太过兴奋,晚上月神做了一个奇怪的梦,月神梦见自己掉入了一个被施放了魔法的深渊,月神想要爬上此深渊。
已知深渊有 N 层台阶构成 ,并且每次月神仅可往上爬2的整数次幂个台阶(1、2、4、....),请你编程告诉月神,月神有多少种方法爬出深渊
数据范围:
,输入的数据组数满足 ![](https://www.nowcoder.com/equation?tex=1%20%5Cle%20m%20%5Cle%201000%20%5C)
输入共有M行
第一行输入一个数M表示有多少组测试数据,
接着有M行,每一行都输入一个 N 表示深渊的台阶数
输出可能的爬出深渊的方式
4 1 2 3 4
1 2 3 6
为了防止溢出,可将输出对10^9 + 3取模
/* 动态规划。类似于跳台阶。 用递归会超时。 取模防止溢出。 */ import java.util.*; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int T = in.nextInt(); int[] dp = new int[1001]; dp[0] = 1; dp[1] = 1; for (int i = 2; i <= 1000; i++) { int tmp = 1; while (tmp <= i) { dp[i] += dp[i - tmp]; tmp *= 2; dp[i] %= 1000000000 + 3; } } while (T-- > 0) { int n = in.nextInt(); System.out.println(dp[n]); } } }
""" 台阶问题考虑动态规划 每次仅可往上爬2的整数次幂个台阶(1、2、4、....) 当前台阶方法数 = 所有一次可到达当前台阶方法数的和 dp[n] = dp[n-1]+dp[n-2]+dp[n-4]+... ( n-t>=0,dp[0]=1 ) """ import sys if __name__ == "__main__": # sys.stdin = open("input.txt", "r") m = int(input().strip()) mod = 1000000003 dp = [0] * 1001 dp[0] = 1 for i in range(1, 1001): t = 1 while t <= i: dp[i] += dp[i - t] dp[i] %= mod t = t * 2 for _ in range(m): n = int(input().strip()) print(dp[n])
#include <iostream> #include <algorithm> using namespace std; long Result[10001] = {0}; //存放各个n对应的结果 long NumOption(int n) { long res = 0; if (n == 0) Result[0] = 1; if (n == 1) Result[1] = 1; if (n == 2) Result[2] = 2; int step = 0; if (Result[n] != 0) return Result[n]; // 若结果里已经有值,直接取出不用递归 while (true) { if (n - pow(2, step) < 0) break; // 循环结束 res += NumOption(n - pow(2, step)); step++; } Result[n] = res % (1000000003); return Result[n]; } int main() { int n; cin >> n; for (int i = 0; i < n; i++) { int in; cin>>in; long res = NumOption(in); cout << res << endl; } return 0; }
#include <bits/stdc++.h> using namespace std; int main() { int m,n[1001],res[1001]; cin>>m; for(int i=0;i<m;i++) cin>>n[i]; vector<int> p = {1,2,4,8,16,32,64,128,256,512}; vector<long long> dp(1001,0); dp[0] = 1; for (int i = 1; i < dp.size();i++) { for (int j = 0; j < p.size();j++) { if (i >= p[j]) { dp[i] = dp[i] + dp[i - p[j]]; dp[i] %= 1000000003LL; } } } for(int i=0;i<m;i++) cout<<dp[n[i]]<<endl; return 0; }
#include <bits/stdc++.h> using namespace std; int main(){ int n; long long dp[1001]={0}; dp[1]=dp[0]=1; for(int i=2;i<=1000;i++){ for(int j=1;j<=i;j<<=1) dp[i]+=dp[i-j]; dp[i]%=1000000000 + 3; } cin>>n; for(int i=0;i<n;i++){ int t; cin>>t; cout<<dp[t]<<endl; } return 0; }
import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner sc=new Scanner(System.in); int M=sc.nextInt(); int[] nums=new int[M]; int max=0; for(int i=0;i<M;i++){ int num=sc.nextInt(); nums[i]=num; max=Math.max(max,num); } int[] dp=new int[max+1]; dp[0]=1; for(int i=1;i<=max;i++){ for(int j=0;i-(int)Math.pow(2,j)>=0;j++){ dp[i]+=dp[i-(int)Math.pow(2,j)]; //经验,可以在每次都取MOD,效果等同于最后取MOD, //好处是能够防止溢出 dp[i]%=1000000003; } } for(int i=0;i<M;i++){ System.out.println(dp[nums[i]]); } } }
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class Solution4_魔法深渊 { final static int MOD = 1000000003; public static void main(String[] args) throws IOException { BufferedReader bf = new BufferedReader(new InputStreamReader(System.in)); int m = Integer.parseInt(bf.readLine()); int[] ans = new int[m]; //保存最大那个数字 求得dp[max],直接在根据输入打印dp中对应的值 int max = 0; for (int i = 0; i < m; i++) { int a = Integer.parseInt(bf.readLine()); if (max<a) max = a; ans[i] = a; } int[] dp = jump(max); for (int i = 0; i < m; i++) { System.out.println(dp[ans[i]]); } } private static int[] jump(int n) { int[] dp = new int[n + 1]; dp[0] = 1; for (int i = 1; i <= n; i++) { for (int j = 1; j <= i; j *= 2) { dp[i] += dp[i - j]; dp[i] = dp[i] % MOD; } } return dp; } }
第6个台阶可以从2,4,5一次性到达,把dp[2],dp[3],dp[4],dp[5]求和即可
第1000个台阶可以从488(1000-512),744(1000-256)...999一次性到达,把dp[488]+...+dp[999]求和即可
#coding=utf-8 def stair(m):#动态规划 import math #导入对数哈函数 re=[]#实现记忆 for n in range(m+1):#从0~m进行计算 if n==0:#边界条件 re.append(1) elif n==1: re.append(1) else: d,s=int(math.log(n,2)),0#找到最接近的2**i,如n=5时,d=2 for i in range(d+1): s+=re[n-2**i]#re[n]=re[n-2**i]+re[n-2**(i-1)]+.....+re[n-2**0] re.append(s) return re[-1] while 1: try: n=int(input()) for i in range(n): print(stair(int(input()))%1000000003)#防止溢而取模 except: break
#include<iostream> (720)#include<vector> using namespace std; int main(void){ int n; cin>>n; int stepNum; vector<int> dp(10001, 0); dp[1] = 1; dp[0] = 1; for (int i = 2; i <= 1000; i++){ int Ex = 1; while (Ex <= i){ dp[i] = (dp[i] + dp[i - Ex]) % (1000000000 + 3); Ex *= 2; } } for (int i = 0; i < n; i++){ cin>>stepNum; cout<<dp[stepNum]<<endl; } return 0; }
n=int(input()) def find(n): dp=[1] for i in range(1,n+1): s=0 for j in range(n): if 2**j<=i: s+=dp[i-2**j] else:break dp.append(s) return dp[-1] for i in range(n): print(find(int(input()))%(10**9 + 3))
import math M = int(input()) mi = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] mod = 1000000003 for i in range(M): n = int(input()) dp = [0]*(n+1) dp[0] = 1 dp[1] = 1 for ni in range(2, n+1): end = int(math.log(ni, 2)) for j in range(0, end+1): dp[ni] += dp[ni-mi[j]] dp[ni] %= mod print(dp[n])
import java.util.*; public class Main{ public static void main(String[] args){ Scanner sc = new Scanner(System.in); int M = Integer.parseInt(sc.nextLine()); for(int i = 0;i<M;i++){ int N = Integer.parseInt(sc.nextLine()); long[] dp = new long[N+1]; dp[0] = 1; for(int j = 1;j<=N;j++){ for(int step : generateSteps(N)){ if(j >= step){ dp[j] = dp[j]+dp[j-step]; dp[j] %= 1000000003; } } } long res = dp[N] % 1000000003; System.out.println(res); } } private static List<Integer> generateSteps(int N){ List<Integer> steps = new ArrayList<>(); int step = 1; while(N > 0){ steps.add(step); N -= step; step *= 2; } return steps; } }
#include<iostream> using namespace std; int dps(int i, int dp[]){ if(dp[i]!=0) return dp[i]; /*//法三,不知为何错误 for(int j=i/2*2;j>=1;j/=2){ dp[i] += dps(i-j, dp); dp[i] %= 1000000003; }*/ //法二 for(int j=1;j<=i;j*=2){ dp[i] += dps(i-j, dp); dp[i] %= 1000000003; } return dp[i]; } int main(){ ios::sync_with_stdio(false); cin.tie(0); int m,n; int dp[1001] = {0}; dp[0]=1;dp[1]=1; /*//法一 for(int i=1;i<=1000;i++){ for(int j=1;j<=i;j*=2){ dp[i] += dp[i-j]; dp[i] %= 1000000003; //防止溢出 } }*/ cin>>m; while(m--){ cin>>n; //cout<<dp[n]<<endl; //法一 cout<<dps(n, dp)<<endl; } return 0; }递归是自上而下,还是自下而上快?