题意
一个数组A = [1, 2, 3, …, n]。
对A进行好恰好k次相邻交换,能得到多少个不同的序列 (S1)?
对A进行最多k次交换,你能得到多少个不同的序列 (S2)?
由于结果很大,输出Mod 1000000007的结果。
1 <= N, K <= 3000
分析
对于第一问,设f[i,j]表示长度为i的排列,交换恰好k次能得到多少不同的序列。
有
f[i,j]=∑jk=max(0,j−i+1)f[i−1,k]
用前缀和优化即可。
第二问,设f[i,j]表示长度为i的排列,有 f[i,j]=f[i−1,j]+f[i−1,j−1]∗(i−1)
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N=3005;
const int MOD=1000000007;
int n,m,f[N][N],s[N];
void solve1()
{
f[1][0]=1;
for (int i=2;i<=n;i++)
{
s[0]=f[i-1][0];
for (int j=1;j<=m;j++) s[j]=s[j-1]+f[i-1][j],s[j]-=s[j]>=MOD?MOD:0;
f[i][0]=f[i-1][0];
for (int j=1;j<=m;j++)
{
f[i][j]=s[j];
if (j>=i) f[i][j]+=MOD-s[j-i],f[i][j]-=f[i][j]>=MOD?MOD:0;
}
}
int ans=0;
for (int i=0;i<=m;i++) if (i%2==m%2) ans+=f[n][i],ans-=ans>=MOD?MOD:0;
printf("%d ",ans);
}
void solve2()
{
f[1][0]=1;
for (int i=2;i<=n;i++)
{
f[i][0]=f[i-1][0];
for (int j=1;j<=m;j++) f[i][j]=f[i-1][j]+(LL)f[i-1][j-1]*(i-1)%MOD,f[i][j]-=f[i][j]>=MOD?MOD:0;
}
int ans=0;
for (int i=0;i<=m;i++) ans+=f[n][i],ans-=ans>=MOD?MOD:0;
printf("%d",ans);
}
int main()
{
scanf("%d%d",&n,&m);
solve1();
solve2();
return 0;
}