【ZOJ3921 2016年浙大2月月赛J】【题目观察 暴力 大组合数】Musical Notes n个数,数值为1 2 4 8 16,和恰为m方案数

Musical Notes Time Limit: 2 Seconds        Memory Limit: 65536 KB

Besides his skills of playing Hearthstone, Bob is also insterested in learning piano in order to make himself more charming, of course, to Alice.

Now, Bob had transcribed a musical score for himself to practice. Unfortunately, he only copied the numbered musical notation, which use numbers 1 to 7 representing the musical notes(sung as do, re, mi...) and he forgot to mark the musical notes, which means he did't know the lengths of those notes. Bob remembered that the composition contains m bar and k quarter rest in the end of the composition. Each bar include 4 beats, and the length of quarter equals one beat. There are 5 other musical notes with differnt lengths——whole note, half note, quarter note, eighth note and sixteenth note. In our cases, the length of a whole note is equal to 4 beats, and the length of others are respectively equal to 2, 1, 1/2 and 1/4 beats in order.

【ZOJ3921 2016年浙大2月月赛J】【题目观察 暴力 大组合数】Musical Notes n个数,数值为1 2 4 8 16,和恰为m方案数_第1张图片
Knowing  m  and  k , he can calculate the whole length of those musical notes,  l  beats, which equals  4*m-k  beats. Then he counted out  n , the number of notes represented by number 1 to 7, with which he may find out how the composition is formed, namely finding out the length of each note. He thought there might be too many cases to form the composition, so he want you to find out the number of possible ways to form the composition.

Input

The first line of input contains an integer T (T ≤ 20) . T is the number of the cases. In the next T lines, there are three integer m, k, n, representing the number of bars, the number of quarter rests, and the number of musical notes.(1 ≤ m ≤ 10000, 0 ≤ k ≤ 3, m  n ≤m+13)

Output

The output contains T lines, and each line contain an answer to a case. The answers might be to large, you should output them modulo 1000000007. If there is no possible ways, output 0.

Sample Input

1
2 0 5

Sample Output

75

Hint

The number of whole, half, quarter, eighth, sixteenth notes can be:

0, 3, 2, 0, 0. In this situation we may find 10 ways to form the composition.

1, 0, 4, 0, 0. In this situation we may find 5 ways.

1, 1, 1, 2, 0. In this situation we may find 60 ways.


#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }
const int N = 10040, M = 0, Z = 1e9 + 7, ms63 = 0x3f3f3f3f;
int casenum, casei;
int m, k, n;
LL fac[N];//阶乘预处理
LL inv[N];//阶乘逆元预处理
void factorial()
{
	int top = 10020;
	fac[0] = 1; for (int i = 1; i <= top; i++)fac[i] = fac[i - 1] * i%Z;
	inv[0] = inv[1] = 1; for (int i = 2; i <= top; i++)inv[i] = inv[Z%i] * (Z - Z / i) % Z;
	for (int i = 2; i <= top; i++)inv[i] = inv[i] * inv[i - 1] % Z;
}
LL C(int n, int m)
{
	return fac[n] * inv[m] % Z*inv[n - m] % Z;
}
int main()
{
	factorial();
	scanf("%d", &casenum);
	for (int casei = 1; casei <= casenum; ++casei)
	{
		scanf("%d%d%d", &m, &k, &n);
		int aim = 4 * m - k;
		int most = 4 * n;

		if (most == n)puts("1");
		else if (most < n)puts("0");
		else
		{
			int ans = 0;
			int more = most - aim;
			//more最大为55
			more *= 4;//最大为220
			for (int i = 0; ; i += 2)//选1,少15
			{
				int I = i * 15;
				if (I > more)break;
				int numI = n - i;
				if (numI < 0)break;
				LL vI = C(n, i);
				for (int j = i / 2 & 1; ; j += 2)//选2,少14
				{
					int J = I + j * 14;
					if (J > more)break;
					int numJ = numI - j;
					if (numJ < 0)break;
					LL vJ = vI*C(numI, j) % Z;
					for (int k = 0; ; ++k)//选4,少12
					{
						int K = J + k * 12;
						if (K > more)break;
						int numK = numJ - k;
						if (numK < 0)break;
						LL vK = vJ*C(numJ, k) % Z;

						if ((more - K) % 8 != 0)continue;//选u,少8
						int u = (more - K) / 8;
						int numU = numK - u;
						if (numU < 0)continue;
						LL vU = vK*C(numK, u) % Z;
						ans = (ans + vU) % Z;
					}
				}
			}
			printf("%d\n", ans);
		}
	}
	return 0;
}
/*
【trick&&吐槽】
观察一些奇怪的限制条件非常重要。
它们常常是题目的突破口!

【题意】
我们有n个的数的数列a[],编号从1到n
它们可能有5种类型的数值,大小分别为4,2,1,1/2,1/4。
它们的总和为4m-k(m为整数,1<=m<=1e4,k∈{0,1,2,3})
它们的总个数为n个,(m<=n<=m+13)
问你,有多少种可能的a[]。

【类型】
题目观察 暴力 大组合数

【分析】
我们发现一个很特殊的限制条件——m<=n<=m+13,
意味着,这n个数,最大能构成的数的取值范围是[4m,4m+52],
而我们实际上只需要构成4m-3,于是我们最多只要减少55的数值差即可。
因为数可能是1/2 或1/4,我们不妨把所有数值都*4,

也就意味着,我们每个数初始都选了16,我们现在要把它们调整为1,2,4,8,
使得数值的减少量为[0,220]范围内的为4倍数的整数。

这里我们就可以做暴力了。
4个数,i,j,k,u
对于数值减少的贡献量依次是15,14,12,8
只要使得15i+14j+12k+8u==more且i+j+k+u<=n

一个暴力即可解决,复杂度不超过20^4

=======================================

最后,因为这n个数两两不同,所以我们要计入组合数的影响。
这个预处理阶乘和逆元,O(1)就可以求得了。

【时间复杂度&&优化】
O(20^4)

*/

你可能感兴趣的:(读题细节找突破,数论-组合数,题库-ZOJ)