HDU-7133 Subpermutation
思路:
首先把排列
p
p
p分成两组,一组是
1
∼
m
1\sim m
1∼m,令一组是
m
+
1
∼
n
m+1\sim n
m+1∼n。
第一种情况:
1
∼
m
1\sim m
1∼m在一个排列内部,那么就相当于把
1
∼
m
1\sim m
1∼m插入
m
+
1
∼
n
m+1\sim n
m+1∼n中包括首尾的任意一个空隙。这两个部分自身也可以任意排列,所以一共有
m
!
(
n
−
m
)
!
(
n
−
m
+
1
)
m!(n-m)!(n-m+1)
m!(n−m)!(n−m+1)种方法。
第二种情况。
1
∼
m
1\sim m
1∼m分成两部分,一部分在尾部,一部分在下一个首部。就相当于把
n
+
1
∼
m
n+1\sim m
n+1∼m插入
1
∼
m
1\sim m
1∼m中不包括首尾的任意一个空隙,同理一共有
m
!
(
n
−
m
!
)
(
m
−
1
)
m!(n-m!)(m-1)
m!(n−m!)(m−1)种方法。
考虑这种情况不合法的方案,那么就是下一个首部会发生改变的时候。我们可以发现,首部发生改变只有一种情况:首部之后的序列是一个递减序列。那么我们可以选
i
i
i个元素作为首部,这样一共就有
∑
i
=
1
m
−
1
(
m
i
)
i
!
\sum\limits_{i=1}^{m-1}\binom{m}{i}i!
i=1∑m−1(im)i!种不合法方案。
所以答案就为:
m
!
(
n
−
m
)
!
n
−
∑
i
=
1
m
−
1
(
m
i
)
i
!
m!(n-m)!n-\sum\limits_{i=1}^{m-1}\binom{m}{i}i!
m!(n−m)!n−i=1∑m−1(im)i!。
这依然是
O
(
n
)
O(n)
O(n)的复杂度,需要稍微化简一下。
预处理阶层,记
f
(
x
)
=
x
!
f(x)=x!
f(x)=x!。
∑
i
=
1
m
−
1
(
m
i
)
i
!
=
∑
i
=
1
m
−
1
m
!
(
m
−
i
)
!
=
∑
i
=
1
m
−
1
m
i
‾
\sum\limits_{i=1}^{m-1}\binom{m}{i}i!=\sum\limits_{i=1}^{m-1}\cfrac{m!}{(m-i)!}=\sum\limits_{i=1}^{m-1}m^{\underline{i}}
i=1∑m−1(im)i!=i=1∑m−1(m−i)!m!=i=1∑m−1mi。
记
g
(
x
)
=
∑
i
=
1
m
m
i
‾
g(x)=\sum\limits_{i=1}^{m}m^{\underline{i}}
g(x)=i=1∑mmi
可以通过
g
(
x
)
=
{
1
x
=
1
x
(
g
(
x
)
+
1
)
x
≥
1
g(x)=\begin{cases}1&x = 1 \\x(g(x)+1)&x\ge1\end{cases}
g(x)={1x(g(x)+1)x=1x≥1预处理。
那么式子就化成了
f
(
m
)
⋅
f
(
n
−
m
)
⋅
n
−
g
(
m
)
+
f
(
m
)
f(m)\cdot f(n-m)\cdot n-g(m)+f(m)
f(m)⋅f(n−m)⋅n−g(m)+f(m)。
代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define int long long
#define mp make_pair
#define pb push_back
#define ls x<<1
#define rs x<<1|1
#define lson x<<1,l,mid
#define rson x<<1|1,mid+1,r
#define pii pair<int,int>
#define all(x) x.begin(),x.end()
#define cl(x,y) memset(x,y,sizeof(x))
#define nxtp(a,n) next_permutation(a+1,a+n+1)
#define mem(x,y,n) memset(x,y,sizeof(int)*(n+5))
const int N=1e6+10;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const double eps=1e-8;
const double pi=acos(-1);
const double INF=1e18;
using namespace std;
int f[N],d[N];
void init()
{
int i,n=1e6+5;
f[0]=f[1]=1;
for(i=2;i<=n;i++)
f[i]=f[i-1]*i%mod;
d[0]=d[1]=1;
for(i=2;i<=n;i++)
d[i]=(d[i-1]+1)*i%mod;
}
signed main()
{
#ifdef ChuTian
clock_t stTime = clock();
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
#endif
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
init();
int T;
cin>>T;
while(T--)
{
int n,m;
cin>>n>>m;
int ans=((f[m]*f[n-m]%mod*n%mod-d[m]+f[m])%mod+mod)%mod;
cout<<ans<<endl;
}
#ifdef ChuTian
cerr << "Time Used:" << clock() - stTime << "ms" <<endl;
#endif
return 0;
}