snnu1111(子序列求和)

1111: 子序列求和

Time Limit: 3 Sec  Memory Limit: 64 MB
Submit: 10  Solved: 2
[Submit][Status][Web Board] [Edit]

Description

给出n个数字,分别为1,2,3,……,n。从中选出t个数字,且这t个数字和为x的方案数为ft,x 。给出m。输出下面的值:
 
数据满足n <= 20000,m <= min(10, n)。

Input

第一行输入T表示测试数据的行数。接下来T行,每行两个数字n, m。T <= 20。

Output

对于每组测试数据,输出一行。

Sample Input

1 4 2

Sample Output

64

HINT

 

 

Source

用d[t][x]表示t个数字和为x的方案数,且这t个数字中的最大数字不超过n。
核心思想 : 给d[t][x]中的每个数字减掉一,变成d[t][x-t],d[t][x]应该等于d[t][x-t].
如果这t个数字中的最小数字为1的话,减去1,最小数字就变为0,相当于t-1个数字,d[t-1][x-t]
,然而这两种情况都未考虑,最大数字不超过n的情况,假设d[t][x-t]中最大数字为n,给这t个数字每个加上1,
那么最大数字就为n+1,超过n,所以,要去掉n+1,这个最大数字,减掉这种情况,相当于减掉d[t-1][x-t].
还有一个坑就是A+B-C,由于要取模,所以A+B可能小于C,(A+B-C+MOD)%MOD;
 (d%MOD+MOD)%MOD;
#include <iostream>

#include <cstdio>

#include <cmath>

#include <cstring>

using namespace std;

#define maxn 21000

#define LL long long

#define MOD  1000000007

int n,m;

LL answer;

LL d[15][maxn*15];

LL f[15];

void init()

{

    memset(d,0,sizeof(d));

    for(int i=1;i<15;i++)

        f[i]=1;

}

LL pow(int a,int b)

{

    LL ans=1;

    for(int i=1;i<=b;i++)

    {

        ans=(ans*a)%MOD;

    }

    return ans;

}

void solve()

{

    for(int i=1;i<=n;i++)

        d[1][i]=1;

        f[1]=pow(2,n);

     // cout<<f[1]<<endl;

     for(int t=2;t<=m;t++)

     {

         for(int x=1;x<(t*n);x++)

        {

            d[t][x]=(d[t][x-t]+d[t-1][x-t]-d[t-1][x-(n+1)] + MOD)%MOD;



            f[t]=(f[t]*(d[t][x]+1))%MOD;

            //printf("%d %d %d\n",t,x,d[t][x]);

        }

        //最小值要么为1,要么不为1,

        //当最小值为1时,最大值可能为n,需要减去d[t-1][x-(n+1)];

        //当最小值不为1,最大值也可能为n,需要减去d[t-1][x-(n+1)];

        //由于这两种情况互斥,所以最多只需要减1次

         //cout<<endl;

       //  while(f[t]<0)

          //cout<<f[t]<<endl;

     }



     answer=0;

     for(int t=1;t<=m;t++)

     {

       //  printf("f %d %d\n",t,f[t]);

          answer=(answer+f[t])%MOD;

          answer=answer%MOD;

     }

    // while(answer<0)

     printf("%lld\n",answer%MOD);

}

int main()

{

   // cout<<(-5)%3<<endl;

    int t;

    scanf("%d",&t);

    while(t--)

    {

       init();

       scanf("%d%d",&n,&m);

       solve();

    }

    return 0;

}

 

你可能感兴趣的:(序列)