hdu 4602 Partition

来源:互联网 发布:模架编程招聘 编辑:程序博客网 时间:2024/05/21 18:39

一道整数划分的问题,,需要利用组合数学

题意是给一个数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;}


0 0
原创粉丝点击