小G的排列-加强版
链接:
题意:
输入样例
4
5 2
3 1
999 666
5555 3333
输出样例
92
0
829050504
284425727
思路:
这里题题意容易理解错,官方题解也不好理解(文字意义上)
首先题中的意思就是说,不能找到一个长度>=m+1的连续段,所以显然就是全排列-含有长度>=m+1的连续段的排列数量,而如何求出长度为n,连续段长度为m的排列数量呢?这里用到了排列组合:
既然算出来了,那么答案就是n!-sol(n,m+1)吗?
很遗憾还是错的,这个地方笔者思考了半天,才想通:
如此答案就是n!-sol(n,m+1)+sol(n,m+2)。
AC代码:
// Problem: 小G的排列-加强版
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/11177/D
// Time Limit: 4000 ms
#include<bits/stdc++.h>
#define ll long long
#define endl "\n"
const int N=1e7+5;
const int INF=0x3f3f3f3f;
const int MOD=1e9+7;
const double eps=1e-6;
using namespace std;
ll n,m;
ll f[N];
ll solve(ll n, ll m){
if(n<m) return 0;
return (n-m+1)*f[n-m+1]%MOD*(m>1?2:1)%MOD; // 注意写成1+m>1?1:0是错的,因为这里1+m变成一个整体了
}
void run(){
cin>>n>>m;
cout<<((f[n]-solve(n,m+1)+MOD)%MOD+solve(n,m+2))%MOD<<endl;
}
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
//freopen("../input.txt","r",stdin);
//freopen("../output.txt","w",stdout);
int _=1;
f[0]=f[1]=1;
for(int i=2;i<N;++i) f[i]=f[i-1]*i%MOD;
cin>>_;
for(int i=0;i<_;++i) run();
return 0;
}