题意:
把所有 n n n元排列按字典序从小到大排成一列,求其中有多少子串为 m m m元排列, t t t组询问。
题解:
(1)考虑单个 n n n元组中的 m m m元组个数。
将 m m m元组看成一个元素,排列组合有 m ! m! m!的情况,现在共有 ( n − m + 1 ) (n-m+1) (n−m+1)个元素,排列组合为 ( n − m + 1 ) ! (n-m+1)! (n−m+1)!。共有 m ! ( n − m + 1 ) ! m!(n-m+1)! m!(n−m+1)!的 m m m元组。
(2)考虑跨两个 n n n元组的 m m m元组个数。
假设 k k k为某个排列中的最后一个使得 p k < p k + 1 > p k + 2 p_k
即 p 1 , p 2 , p 3 . . . p k < p k + 1 > p k + 2 > p k + 3 . . . > p n p_1,p_2,p_3...p_k
那么下一个字典序的排列为:
p 1 , p 2 , p 3... p j < p n < . . . < p j + 1 < p k < p j − 1 < . . . . < p k + 1 ( p j > p k ) p1,p2,p3...p_j
假设 i i i为我们所要的 m m m元组开头的位置。
1.当 i < = k i<=k i<=k时:
第一个排列中存在 n − i + 1 n-i+1 n−i+1个数,剩下的数在第二排列中,因为 m < n m
因为 i < = k i<=k i<=k所以在 [ i , n ] [i,n] [i,n]内必须存在一个位置 k k k使得 p k < p k + 1 p_k
也就是 m ! ( 全 部 的 方 案 ) − ∁ m n − i + 1 ( m − ( n − i + 1 ) ) ! ( m 个 数 选 出 n − i + 1 个 数 在 第 一 个 排 列 中 , 且 为 降 序 排 列 的 方 案 ) m!(全部的方案)-\complement_m^{n-i+1}(m-(n-i+1))!\ (m个数选出n-i+1个数在第一个排列中,且为降序排列的方案) m!(全部的方案)−∁mn−i+1(m−(n−i+1))! (m个数选出n−i+1个数在第一个排列中,且为降序排列的方案)
剩下的 n − m n-m n−m个数随便排列。
于是此时的方案数为 ( n − m ) ! ( m ! − ∁ m n − i + 1 ( m − ( n − i + 1 ) ) ! ) (n-m)!(m!-\complement_m^{n-i+1}(m-(n-i+1))!) (n−m)!(m!−∁mn−i+1(m−(n−i+1))!)
2.当 i > = k + 1 i>=k+1 i>=k+1时:
此时 p k p_k pk不在 m m m元组中, p k > m p_k>m pk>m,而 p j > p k > m p_j>p_k>m pj>pk>m,所以 p j p_j pj也不再 m m m元组中。
同样:(标黄的是m元组出现的范围)
p 1 , p 2 , p 3 . . . p k < p k + 1 > p_1,p_2,p_3...p_k
那么下一个字典序的排列为:
p 1 , p 2 , p 3 p1,p2,p3 p1,p2,p3 . . . p j < p n < . . . < p j + 1 < p k < p j − 1 < . . . . < p k + 1 ( p j > p k ) ...p_j
这就意味着在第二个排列中,最后一个元素的下标为 i + m − 1 − n < j i+m-1-n
前 n − i + 1 n-i+1 n−i+1个数是递减的,剩下 ( m − ( n − i + 1 ) ) (m-(n-i+1)) (m−(n−i+1))个数没有限制,方案数为 ( m − ( n − i + 1 ) ) ! (m-(n-i+1))! (m−(n−i+1))!。对于 m m m元组以外的 m − n m-n m−n个数,必须存在一个 k k k使得 p k < p k + 1 p_k
i i i的范围:
第一个排列中的数要小于 m m m.
( n − i + 1 ) > = m − 1 , i > = n + 2 − m (n-i+1)>=m-1,i>=n+2-m (n−i+1)>=m−1,i>=n+2−m
最后答案就是 m ! ( n − m + 1 ) ! + ∑ i = n + 2 − m n ( ( n − m ) ! ( m ! − ∁ m n − i + 1 ( m − ( n − i + 1 ) ) ! ) + ∁ m n − i + 1 ( m − ( n − i + 1 ) ) ! ( ( n − m ) ! − 1 ) ) m!(n-m+1)!+\sum_{i=n+2-m}^n((n-m)!(m!-\complement_{m}^{n-i+1}(m-(n-i+1))!) +\complement_{m}^{n-i+1}(m-(n-i+1))!((n-m)!-1)) m!(n−m+1)!+∑i=n+2−mn((n−m)!(m!−∁mn−i+1(m−(n−i+1))!)+∁mn−i+1(m−(n−i+1))!((n−m)!−1))
化简得: m ! ( n − m + 1 ) ! + ( m − 1 ) ( n − m ) ! m ! − m ! ∑ i = 1 m − 1 1 i ! m!(n-m+1)!+(m-1)(n-m)!m!-m!\sum_{i=1}^{m-1}\frac{1}{i!} m!(n−m+1)!+(m−1)(n−m)!m!−m!∑i=1m−1i!1
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long
#define maxn 1000005
#define mod 1000000007
#define MOD 998244353
#define Mod 1000000009
#define eps 1e-10
const ll inf=0x3f3f3f3f3f3f3f3f;
const ll INF=0x3f3f3f3f;
const ll mod1=1e9+7;
const ll mod2=1e9+9;
template <typename T>
inline void read(T& X) {X = 0; int w = 0; char ch = 0;while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();if (w) X = -X;}
char F[200];inline void write(int x){if(x == 0){putchar('0');return;}int tmp = x > 0 ? x : -x;int cnt = 0;if(x < 0)putchar( '-' );while(tmp > 0){F[cnt++] = tmp % 10 + '0';tmp /= 10;}while(cnt > 0)putchar(F[--cnt]) ;}
template<typename T> void print(T x){if(x>9) print(x/10);putchar(x%10+'0');}
ll q_pow(ll x,ll y,ll M){ll ans=1;while(y){if(y%2){y--;ans=ans*x%M;}else {y/=2;x=x*x%M;}}return ans;}
ll a[maxn],b[maxn],f[maxn];
void init(){
a[0]=1;
for(ll i=1;i<=1000000;i++)a[i]=a[i-1]*i%mod;
b[1000000]=q_pow(a[1000000],mod-2,mod);
for(ll i=999999;i>=0;i--)b[i]=b[i+1]*(i+1ll)%mod;
for(int i=1;i<=1000000;i++)f[i]=(f[i-1]+b[i])%mod;
}
ll C(ll n,ll m){
return a[n]*b[m]%mod*b[n-m]%mod;
}
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int t;
ll n,m;
init();
cin>>t;
while(t--){
cin>>n>>m;
ll ans=a[m]*a[n-m+1]%mod+(m-1)*a[n-m]%mod*a[m]%mod-a[m]*f[m-1]%mod;
ans=(ans%mod+mod)%mod;
cout<<ans<<"\n";
}
return 0;
}