有趣的数(组合计数问题)

我们把一个数称为有趣的,当且仅当:
1、它的数字只包含 0,1,2,3,且这四个数字都出现过至少一次。
2、所有的 0 都出现在所有的 1 之前,而所有的 2 都出现在所有的 3 之前。
3、最高位数字不为 0。
因此,符合我们定义的最小的有趣的数是 2013。
除此以外,4 位的有趣的数还有两个:2031 和 2301。

请计算恰好有 n 位的有趣的数的个数。
由于答案可能非常大,只需要输出答案除以 109+7 的余数。

输入格式
输入只有一行,包括恰好一个正整数 n。

输出格式
输出只有一行,包括恰好 n 位的整数中有趣的数的个数除以 109+7 的余数。

数据范围
4≤n≤1000


思路:
列出限制条件:
在这里插入图片描述

根据最特殊的第二条,把所有数分为两类:01一类,23 一类
一共有n位数,设01一共有k位数,则23有n-k位数,由于第一个条件的限制,有2<=k<=n-2,所以枚举k,将算出来的个数相加,得到的就是总个数

来看当01有k位,23有n-k位时怎么算个数?
因为保证所有的0在1之前,2在3之前,所以0和1,2和3的相对位置不会改变,当所有01的位置填好后,剩下的就是23的位置
因为最高位不能为0,所以01的所有可能位置就是在除最高位的n-1个位置中选出来k个的选法:C(n-1,k)。然后在乘上所有不同的01组合,因为01一共有k位,0可能有m个1<=m<=k-1,一共有k-1种可能;最后在乘上所有不同的23组合,因为23一共有n-k位,2可能有m个1<=m<=n-k-1,一共有n-k-1种可能。
所以当01有k位,23有n-k位时,个数为C(n-1,k)×(k-1)×(n-k-1)

然后枚举k把所有的加起来就好了

const int N = 1e3+5, mod = 1e9+7;

int n,c[N][N];

void init()
{
    
    
	for(int i=0;i<N;i++)
		for(int j=0;j<=i;j++)
			if(j==0)	c[i][j]=1;
			else	c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}

int main()
{
    
    
    init();
    
	cin>>n;
	
	int ans=0;
	for(int k=2;k<=n-2;k++)
		ans=(ans+ (ll)c[n-1][k]*(k-1)%mod*(n-k-1))%mod;

	cout<<ans<<endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_50815157/article/details/113833560