Description
有 n ( n ≤ 500000 ) n(n\le 500000) n(n≤500000) 个人排成一列,把他们解散后重排,使得"重排后前方" 跟"原排列前方" 一样的人不超过 k ( k < n ) k(k<n) k(k<n) 个,问有几种方法数,答案请 m o d ( 1 0 9 + 7 ) mod (10^9+7) mod(109+7) 输出。
举例来说,有五个人编号为 1 1 1∼ 5 5 5 间的整数,最初的排列由前至后依序为 1 , 2 , 3 , 4 , 5 1, 2, 3, 4, 5 1,2,3,4,5,重排列后顺序由前至后变为 1 , 3 , 4 , 2 , 5 1, 3, 4, 2, 5 1,3,4,2,5,其中只有编号为 4 4 4 的人,“原排列前方” 跟"重排后前方" 都是编号为 3 3 3 的人,故"重排后前方" 跟"原排列前方" 一样的人只有 1 1 1人。
原排列的第 1 1 1个人和重排后的第 1 1 1个人一定不会是「“重排后前方” 跟 “原排列前方” 一样的人」。
Input
输入只有一行,有两个正整数 n , k n,k n,k,满足 1 ≤ k < n ≤ 500000 1\le k<n\le 500000 1≤k<n≤500000。
Output
请输出一行包含一个小于$10^9+7 $的非负整数,表示总共的方法数 m o d ( 1 0 9 + 7 ) mod (10^9+7) mod(109+7)。
Sample Input
3 1
Sample Output
5
Solution
令 a n a_n an为 n n n个人重排后前方的人均不是原排列前方人的方案数,假设起初排位为 1 , . . . , n 1,...,n 1,...,n,考虑 1 1 1的作用
1. 1. 1.若 1 1 1不再任意一对 i , i + 1 i,i+1 i,i+1之间,那么需要 2 2 2~ n n n这 n − 1 n-1 n−1个人重排后前方的人均不是原排列前方的人,方案数为 a n − 1 a_{n-1} an−1,对于这其中的每一种方案,只要 1 1 1不在 2 2 2前方即可,故 1 1 1有 n − 1 n-1 n−1个位置可以放
2. 2. 2.若 1 1 1在某对 i , i + 1 i,i+1 i,i+1之间,选择一个 i i i方案数为 n − 2 n-2 n−2,之后把 i , 1 , i + 1 i,1,i+1 i,1,i+1看作一个元素 i + 1 i+1 i+1,问题转化为 n − 2 n-2 n−2个人重排后每个人前方的人均不是原排列前方的人,方案数 a n − 2 a_{n-2} an−2
综上有 a n = ( n − 1 ) ⋅ a n − 1 + ( n − 2 ) ⋅ a n − 2 a_n=(n-1)\cdot a_{n-1}+(n-2)\cdot a_{n-2} an=(n−1)⋅an−1+(n−2)⋅an−2,线性预处理 a n a_n an即可
之后考虑原问题,假设重排后有 x x x个人前方的人和原排列前方的人相同,从 n − 1 n-1 n−1个有前方人的人中选出这 x x x个人方案数 C n − 1 x C_{n-1}^x Cn−1x,选出后,把这 x x x对看作 x x x个元素,问题转化为 n − x n-x n−x个人重排后每个人前方的人均不是原排列前方人的方案数,即 a n − x a_{n-x} an−x,故答案为 ∑ x = 0 k C n − 1 x ⋅ a n − x \sum\limits_{x=0}^kC_{n-1}^x\cdot a_{n-x} x=0∑kCn−1x⋅an−x
Code
#include<cstdio>
using namespace std;
typedef long long ll;
const int maxn=500005;
#define mod 1000000007
int add(int x,int y)
{
x+=y;
if(x>=mod)x-=mod;
return x;
}
int mul(int x,int y)
{
ll z=1ll*x*y;
return z-z/mod*mod;
}
int n,k,a[maxn],inv[maxn],fact[maxn];
void init(int n=5e5)
{
inv[1]=1;
for(int i=2;i<=n;i++)inv[i]=mul(mod-mod/i,inv[mod%i]);
inv[0]=1;
for(int i=1;i<=n;i++)inv[i]=mul(inv[i-1],inv[i]);
fact[0]=1;
for(int i=1;i<=n;i++)fact[i]=mul(i,fact[i-1]);
}
int C(int n,int m)
{
return mul(fact[n],mul(inv[m],inv[n-m]));
}
int main()
{
init();
scanf("%d%d",&n,&k);
a[1]=1,a[2]=1;
for(int i=3;i<=n;i++)a[i]=add(mul(i-1,a[i-1]),mul(i-2,a[i-2]));
int ans=0;
for(int i=0;i<=k;i++)ans=add(ans,mul(C(n-1,i),a[n-i]));
printf("%d\n",ans);
return 0;
}