给出
n
≤
1
e
3
n\leq1e3
n≤1e3,求长度为
n
n
n的全排列当中逆序对为
k
k
k的个数有多少个。
又是一个不太熟悉的套路。由于是全排列,所有的元素都是互异的。而且逆序对只用考虑相对的位置,也就是这里的具体的值其实不重要。
用
f
i
,
j
f_{i,j}
fi,j表示前
i
i
i个元素有
j
j
j个逆序对的方案数。当前的这一位放进来,可以产生
0
0
0到
i
−
1
i-1
i−1个逆序对。
f
i
,
j
=
∑
k
=
i
−
(
j
−
1
)
j
f
i
−
1
,
k
f_{i,j}=\sum\limits_{k=i-(j-1)}^{j}f_{i-1,k}
fi,j=k=i−(j−1)∑jfi−1,k。这个复杂度是
O
(
n
k
2
)
O(nk^2)
O(nk2)的,前缀和优化一下可以做到
O
(
n
k
)
O(nk)
O(nk)。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=1e3+7;
const int mod=1e4;
int f[N][N];
int main() {
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
f[i][0]=1;
for(int i=2;i<=n;i++) {
int sum=f[i-1][0];
for(int j=1;j<=k;j++) {
sum+=f[i-1][j];
sum%=mod;
if(j-i+1>0) {
sum-=f[i-1][j-i];
sum+=mod;
sum%=mod;
}
f[i][j]+=sum;
f[i][j]%=mod;
// for(int k=max(0,j-i+1);k<=j;k++) {
// f[i][j]+=f[i-1][k];
// f[i][j]%=mod;
// }
}
}
printf("%d\n",f[n][k]);
return 0;
}