HDU-7133 Subpermutation

HDU-7133 Subpermutation

思路:

首先把排列 p p p分成两组,一组是 1 ∼ m 1\sim m 1m,令一组是 m + 1 ∼ n m+1\sim n m+1n
第一种情况:
1 ∼ m 1\sim m 1m在一个排列内部,那么就相当于把 1 ∼ m 1\sim m 1m插入 m + 1 ∼ n m+1\sim n m+1n中包括首尾的任意一个空隙。这两个部分自身也可以任意排列,所以一共有 m ! ( n − m ) ! ( n − m + 1 ) m!(n-m)!(n-m+1) m!(nm)!(nm+1)种方法。
第二种情况。
1 ∼ m 1\sim m 1m分成两部分,一部分在尾部,一部分在下一个首部。就相当于把 n + 1 ∼ m n+1\sim m n+1m插入 1 ∼ m 1\sim m 1m中不包括首尾的任意一个空隙,同理一共有 m ! ( n − m ! ) ( m − 1 ) m!(n-m!)(m-1) m!(nm!)(m1)种方法。
考虑这种情况不合法的方案,那么就是下一个首部会发生改变的时候。我们可以发现,首部发生改变只有一种情况:首部之后的序列是一个递减序列。那么我们可以选 i i i个元素作为首部,这样一共就有 ∑ i = 1 m − 1 ( m i ) i ! \sum\limits_{i=1}^{m-1}\binom{m}{i}i! i=1m1(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!(nm)!ni=1m1(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=1m1(im)i!=i=1m1(mi)!m!=i=1m1mi
g ( x ) = ∑ i = 1 m m i ‾ g(x)=\sum\limits_{i=1}^{m}m^{\underline{i}} g(x)=i=1mmi
可以通过 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=1x1预处理。
那么式子就化成了 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(nm)ng(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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值