Codeforces Round #144 (Div. 1) B dp

来源:互联网 发布:纪念日软件 编辑:程序博客网 时间:2024/06/06 03:16
//第i列和第i+n的涂色个数是相同的,所以只需要处理前n列
//dp[i][j]表示前i列有j个涂色的方法数
//dp[i][j] += dp[i-1][s]*pow(c[n][s] , m/n)  
//c[n][s] 表示从n个数中取s的组合数
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std ;
const int maxn = 110 ;
const __int64 mod =  1000000007;
__int64 dp[maxn][maxn*maxn];
__int64 c[maxn][maxn] ;
__int64 po[maxn][maxn*maxn][2] ;
__int64 pow(__int64 a ,__int64 b)
{
    __int64 c = 1;
    while(b)
    {
        if((b&1)) c=((c%mod)*(a%mod))%mod;
        a=((a%mod)*(a%mod))%mod ;
        b = b>>1;
    }
    return c;
}
void init()
{
    memset(dp , 0 , sizeof(dp)) ;
    for(int i = 0;i <= 100;i++)
    {
        c[i][0] = 1;
        for(int j = 1; j <= i;j++)
        c[i][j] = (c[i-1][j] + c[i-1][j-1])%mod ;
    }
}
int main()
{
    __int64 m ;
    int  n , k;
    while(~scanf("%d%I64d%d",&n ,&m ,&k))
    {
        init();
        int res =  m%n ;
        for(int i =0;i <= n ;i++)
        dp[i][0] = 1 ;
        for(int i = 1;i <= n;i++)
            for(int s = 0;s <= k;s++)
            {
               if(i <= res)
               po[i][s][0] = pow(c[n][s] , m/n+1);
               else
               po[i][s][1] = pow(c[n][s] ,m/n);


            }


        for(int i = 1;i <= n;i ++)
        {
            for(int j = 1;j <= k;j++)
            {
                for(int s = 0;s <= min(j ,n); s++)
                {
                    if(i <= res)
                    dp[i][j] = (dp[i][j] + dp[i-1][j-s]*po[i][s][0])%mod ;
                    else
                    dp[i][j] = (dp[i][j] + dp[i-1][j-s]*po[i][s][1])%mod ;
                }
            }
        }
        printf("%I64d\n" ,dp[n][k]) ;
    }
    return 0;
}





























































0 0