鉴于确切的没有。必须存在于数组中的元素(let = r)和数组的最后一个元素的最大值(let = n)找到可能的不同非减少数组的总数(数组的所有元素必须是> = 0)
示例 - 如果r = 3且n = 2,那么一些可能的非递减数组是{0,0,2},{0,0,1},{0,0,0},{1,2,2等等 我需要不。这种阵列的可能性。
我尝试使用递归和memoization来解决它,但它太慢了。
这是我的代码( ll表示很长) -
ll solve(ll i,ll curlevel)
{
if(dp[i][curlevel]!=-1)
return dp[i][curlevel];
if(i<0)
return dp[i][curlevel]=0;
if(curlevel==r)
return dp[i][curlevel]=1;
if(curlevel>r)
return dp[i][curlevel]=0;
ll ans=0;
for(ll k=i;k>=0;k--)
{
ans+= solve(k, curlevel+1);
}
return dp[i][curlevel]=ans;
}
我将此功能称为如下。
for(ll i=n;i>=0;i--)
{
res+=solve(i, 1);
}
我正在寻找一种更快捷的方法。
答案 0 :(得分:1)
不是为了添加的部分:它归结为非下降顺序允许重复的组合。对于n
,我们有0-n
个符号(即n+1
个符号)和r
个长度。在中间和this answer上math.stackexchange,我们得到一个简单的公式:
答案 1 :(得分:1)
让我们采取一些符合条件的非递减序列,并使用0和1对其进行编码。解码算法很简单:
现在,我声称任何非递减序列都可以使用精确r
0的序列进行编码(因为我们需要准确输出r
个值)和{ {1}} 1s(因为我们不能超过值n
),并且每个这样的编码序列对应于唯一的非递减序列。 (编码算法和双射证明留作练习。)
因此,未编码序列的数量与编码序列的数量相同。但编码序列的数量只是选择n
位置从编码序列中的r
位置插入0的方式的数量。因此,可能性的数量为n+r
选择n+r
或r
。
这些数字迅速增长,你需要使用bignum算法来计算它们,即使是中等大小的(n+r)!/(n!*r!)
和r
也是如此。例如,如果n
和n
都是2000,那么序列的计数是一个1203位的数字,大约是1.66 * 10 1202 。
显然,尝试枚举一组这样大小的序列是徒劳的。对于r
和r
的小值,序列可以按照每个序列的摊销时间O(1)进行枚举,使用标准的词典编纂算法,该算法采用序列并按字典顺序生成下一个序列:
找到可以变大的序列中最右边的元素。 (在这种情况下,找到序列中最右边的元素不等于n
。)如果没有这样的元素,则枚举所有序列。
推进已找到的元素。 (在这种情况下,为元素添加1。)
将所有后续元素(如果有)设置为其最小可能值。 (在这种情况下,将所有后续元素设置为步骤1中找到的元素的新值。