【Table】【CodeForces - 232B】

版权声明:本人原创,未经许可,不得转载 https://blog.csdn.net/qq_42505741/article/details/83756894

题目:

John Doe has an n × m table. John Doe can paint points in some table cells, not more than one point in one table cell. John Doe wants to use such operations to make each square subtable of size n × n have exactly k points.

John Doe wondered, how many distinct ways to fill the table with points are there, provided that the condition must hold. As this number can be rather large, John Doe asks to find its remainder after dividing by 1000000007 (109 + 7).

You should assume that John always paints a point exactly in the center of some cell. Two ways to fill a table are considered distinct, if there exists a table cell, that has a point in one way and doesn't have it in the other.

Input

A single line contains space-separated integers nmk (1 ≤ n ≤ 100; n ≤ m ≤ 1018; 0 ≤ k ≤ n2) — the number of rows of the table, the number of columns of the table and the number of points each square must contain.

Please, do not use the %lld specifier to read or write 64-bit integers in С++. It is preferred to use the cin, cout streams or the %I64d specifier.

Output

In a single line print a single integer — the remainder from dividing the described number of ways by 1000000007 (109 + 7).

Examples

Input

5 6 1

Output

45

Note

Let's consider the first test case:

The gray area belongs to both 5 × 5 squares. So, if it has one point, then there shouldn't be points in any other place. If one of the white areas has a point, then the other one also must have a point. Thus, there are about 20 variants, where the point lies in the gray area and 25 variants, where each of the white areas contains a point. Overall there are 45 variants.

解题报告:刚上来确实是没有理解题目的意思,后来看懂了,但是也只是理解了当k=1 的情况,所以很迷,之后又想了很久,这道题目卡了一个半小时,后来理解了,就是给定我们一个n*m的大矩阵,要求每个n*n的矩阵中都要有至少k个点,问放法的数量。发现了规律,第i列和第i+n行的放置个数是相同的,之后采用dp,dp[i][k]表示第i列放置了k个点了。会得到一个规律就是

在那列放置j个点的情况下,dp[i][k]+=dp[i-1][k-j]*C(n,j)^cnt;(j是需要枚举的,cnt是周期的数目)

ac代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
ll num[200][200];
ll dp[250][15000];
ll n,m,k;
ll ksm(ll a,ll b)
{
	ll res=1;
	while(b)
	{
		if(b&1)
		{
			res=(res*a)%mod;
			b--;
		}
		a=(a*a)%mod;
		b>>=1;
	}
	return res;
}

int main()
{
	scanf("%lld%lld%lld",&n,&m,&k);
	for(int i=1;i<=100;i++)
	{
		num[i][0]=1;
		num[i][i]=1;
		num[i][1]=i;
	}
	for(int i=2;i<=100;i++)
		for(int j=2;j<i;j++)
		{
			num[i][j]=(num[i-1][j]+num[i-1][j-1])%mod;
		}//组合数打表求值
	/*for(int i=0;i<=n;i++)
	{
		for(int j=0;j<=m;j++)
			printf("%lld ",num[i][j]);
		printf("\n");
	}*/
	memset(dp,0,sizeof(dp));
	ll cnt=m/n;
	ll gb;
	if(m%n)
	{
		gb=m-cnt*n;
		cnt++;
	}
	else 
		gb=n;
	for(int i=0;i<=n;i++)
		dp[i][0]=1;
	for(int i=1;i<=n;i++)
		for(int j=0;j<=n&&j<=k;j++)
		{
			ll gg=num[n][j];
			ll gd;
			if((ll)i<=gb) gd=ksm(gg,cnt);
			else  gd=ksm(gg,cnt-1);
			for(int ll=j;ll<=k;ll++)
			{
				if(ll==0) continue;
				dp[i][ll] +=  dp[i-1][ll-j]*gd;
				dp[i][ll]%=mod;
			}
		}
/*	for(int i=0;i<=n;i++)
	{
		for(int j=0;j<=m;j++)
			printf("%lld ",dp[i][j]);
		printf("\n");
	}*/
	printf("%lld\n",(dp[n][k]+mod)%mod);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42505741/article/details/83756894
今日推荐