一道整数划分的问题,,需要利用组合数学
题意是给一个数n,有2^(n-1)中划分方法,问在这2^(n-1)种方法中数字m出现的次数
例如
3=1+1+1
3=1+2
3=2+1
3=3
则2出现的次数为2.
刚开始想的是利用递推的方式,但是地推的方式不对,变量多一两个我就处理不过来了,唉~~其实是利用排列组合的知识,隔板法
分两种情况:(将n划分为n个1,则连续取m个1)
第一:当取得连续m个数位于首或尾时,就有2^(n-m-1)种取法
第二:当取得的连续数位于中间段时,就有2^(n-m-2)种取法,
所以可以得出公式=(n-m-1)*2^(n-m-2)+2*2^(n-m-1)=(n-m+3)*2^(n-m-2)
注意当n=m,m=1,n-m=1,m>n时特判一下,其实每一种取法就对应在这个位置上出现多少次,无关其他位置的取值,所以把每个位置的取法相加就等于出现的次数了,刚开始时看题解的时候很不明白,忘了是要求出现的次数,我以为求取法所以在相加这个地方纠结了好久,脑子不好使的痛苦~~~(复习了快速幂的写法)
这是另外一种解释:点击打开链接
#include<stdio.h>
#include<string.h>
#include <iostream>
using namespace std;
typedef long long LL;
const LL mod=1e9+7;
LL quick(LL n,LL p)
{
LL ans=1;
while(p>0)
{
if(p&1)
ans=(ans*n)%mod;
p>>=1;
n=(n*n)%mod;
}
return ans;
}
int main()
{
int t;
LL n,k;
scanf("%d",&t);
while(t--)
{
scanf("%I64d%I64d",&n,&k);
if(k>n)
printf("0\n");
else if(n==k)
printf("1\n");
else if(n-k==1)
printf("2\n");
else
{
//cout<<quick(2,n-k-2)<<endl;
LL sum=(quick(2,n-k-2)*(n-k+3))%mod;
printf("%I64d\n",sum);
}
}
return 0;
}
本文探讨了一道整数划分问题,通过组合数学的方法计算特定数字在所有可能的划分方式中出现的总次数,并给出了具体的算法实现。

被折叠的 条评论
为什么被折叠?



