计数使用长度为1,2,3,4,...... m的步长达到第N步的方法数(其中m <= n)

时间:2015-08-18 08:06:10

标签: c++ algorithm combinations permutation combinatorics

我给了一个数字n的订单10 5 。我要找到一些方法,使用长度1 or 2 or 3 or.....or m的步长从地面到达n th 步骤,这里m <= n。

由于答案可能太大,因此模数 10 9 +7

#include<iostream.h>
using namespace std;

#define ll long long
#define MOD 1000000007

ll countWays_(ll n, ll m){
    ll res[n];
    res[0] = 1; res[1] = 1;
    for (ll i=2; i<n; i++)
    {
       res[i] = 0;
       for (ll j=1; j<=m && j<=i; j++)
         res[i] =(res[i]%MOD+ res[i-j]%MOD)%MOD;
    }
    return res[n-1];
}

ll countWays(ll s, ll m){
    return countWays_(s+1, m);
}
int main (){
    scanf("%lld%lld",&s,&m);
    printf("%lld\n",countWays(s,m));
    return 0;
}

由于复杂性O(m*n),我想减少它。

2 个答案:

答案 0 :(得分:5)

您的内部循环将res[i-1] + res[i-2] + ... + res[i-m]添加到结果中。

si中第一个res元素的总和。然后,您只需将s[i-1] - s[i-m-1]添加到结果中即可。

ll countWays_(ll n, ll m){
    ll res[n];
    res[0] = 1; res[1] = 1;
    s[0] = 1; s[1] = 2;
    for (ll i=2; i<n; i++)
    {
       if (i <= m)
           res[i] = s[i-1] % MOD;
       else
           res[i] = (s[i-1] - s[i - m - 1] + MOD) % MOD; 
       s[i] = (s[i-1] + res[i]) % MOD;
    }
    return res[n-1];
}

新的复杂性将为O(n)。您甚至可以将s作为数组删除,并使用单个变量和更多的簿记。

答案 1 :(得分:2)

我认为使用可以使用变量Sum来存储res形式i-m + 1的总和,如下所示:

ll mod(ll a, ll b){ 
    return (a%b+b)%b; 
}
ll countWays_(ll n, ll m){
    ll res[n],sum;
    res[0] = 1; res[1] = 1;
    sum = res[0] + res[1];
    int head_sum = 0;
    for (ll i=2; i<n; i++)
    {
       if ((i - head_sum) > m) {
            sum=mod((sum- res[head_sum]),MOD);
            head_sum++;
       }  
       res[i] = sum;
       sum = mod((sum% MOD + res[i]% MOD),MOD);
    }
    return res[n-1];
}