牛客练习赛87 D.小G的排列-加强版(思维,组合数学)
Posted issue是fw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了牛客练习赛87 D.小G的排列-加强版(思维,组合数学)相关的知识,希望对你有一定的参考价值。
考虑用 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 n−m+1种,把这个看成一个元素和其他 n − m n-m n−m个元素排列
得到 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)=(n−m+1)∗(n−m+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的排列-加强版(思维,组合数学)的主要内容,如果未能解决你的问题,请参考以下文章