牛客练习赛87 D.小G的排列-加强版(思维,组合数学)

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了牛客练习赛87 D.小G的排列-加强版(思维,组合数学)相关的知识,希望对你有一定的参考价值。

LINK

考虑用 n ! n! n!减去大于等于 m + 1 m+1 m+1连续段的排列数

s o l ( n , m ) sol(n,m) sol(n,m)表示长度为 n n n的所有排列中,长度为 m m m的连续段出现过多少次

由于长度为 m m m的连续段有 n − m + 1 n-m+1 nm+1种,把这个看成一个元素和其他 n − m n-m nm个元素排列

得到 s o l ( n , m ) = ( n − m + 1 ) ∗ ( n − m + 1 ) ! ∗ ( 1 + [ m > 1 ] ) sol(n,m)=(n-m+1)*(n-m+1)!*(1+[m>1]) sol(n,m)=(nm+1)(nm+1)!(1+[m>1])

其中 m > 1 m>1 m>1那么这个长度为 m m m的连续段还可以翻转,但是当 m = 1 m=1 m=1时翻转了和没翻转一样

考虑一个长度为 n n n的排列中存在一个长度为 k k k的连续段( k > = m + 1 k>=m+1 k>=m+1)

它恰好包含 k − ( m + 1 ) + 1 k-(m+1)+1 k(m+1)+1个长度大于等于 m + 1 m+1 m+1的连续段

也恰好包含 k − ( m + 2 ) + 1 k-(m+2)+1 k(m+2)+1个长度大于等于 m + 2 m+2 m+2的连续段

因此 s o l ( n , m + 1 ) − s o l ( n , m + 2 ) sol(n,m+1)-sol(n,m+2) sol(n,m+1)sol(n,m+2)就是所有排列中存在长度大于等于 m + 1 m+1 m+1的连续段的方案数

所以答案是 n ! − (   s o l ( n , m + 1 ) − s o l ( n , m + 2 )   ) n!-(\\ sol(n,m+1)-sol(n,m+2)\\ ) n!( sol(n,m+1)sol(n,m+2) )

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e7+10;
const int mod = 1e9+7; 
const int N = 59;
int t,n,m,fac[maxn];
int sol(int n,int m)
{
	if( m>n )	return 0ll;
	return 1ll*(n-m+1)*fac[n-m+1]%mod*(1+(m>1) )%mod;
}
signed main()
{
	fac[0] = 1;
	for(int i=1;i<maxn;i++)	fac[i] = 1ll*fac[i-1]*i%mod;	
	cin >> t;
	while( t-- )
	{
		cin >> n >> m;
		cout << (( 1ll*fac[n]-sol(n,m+1)+sol(n,m+2) )%mod+mod )%mod << endl;
	}
}

以上是关于牛客练习赛87 D.小G的排列-加强版(思维,组合数学)的主要内容,如果未能解决你的问题,请参考以下文章

牛客练习赛81 D.小 Q 与树(点分治+容斥)

牛客练习赛82 B.Mocha 的序列(小思维,同余)

牛客练习赛84 D.牛客推荐系统开发之动态特征获取(set应用)

牛客练习赛105 D.点分治分点(spfa&bfs)

牛客练习赛85 D.数学家的迷题(bitset暴力)

牛客练习赛56 D.小翔和泰拉瑞亚 线段树