题意概括
题面很清楚,不多赘述了。
分析
设 f i , j f_{i,j} fi,j 表示已用前 i i i 个数,使数列出现 j j j 个逆序对的方案数。
因为从小到大枚举 i i i,所以填 i i i 时前面所有的数都比它小,那么 i i i 每向前移动一位,就会增加一个逆序对。所以可以直接枚举每一个 i , j i,j i,j,再枚举插入 i i i 的位置,转移方程是 f i , j = ∑ k = 0 i − 1 f i − 1 , j − k f_{i,j}=\sum\limits_{k=0}^{i-1} f_{i-1,j-k} fi,j=k=0∑i−1fi−1,j−k。但这样是 O ( n c 2 ) O(nc^2) O(nc2) 的,会 TLE。
但是可以发现,第三维就是在找 [ j − i + 1 , i − 1 ] [j-i+1,i-1] [j−i+1,i−1] 的区间,所以可以加入一个前缀和,把复杂度优化到 O ( n c ) O(nc) O(nc),通过这道题。
Code
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const ll mod=1e9+7;
ll n,c,f[10005]={1},s[10005];
signed main(){
cin>>n>>c;
for(ll i=2;i<=n;++i){
s[0]=f[0];
for(ll j=1;j<=c;++j)s[j]=(s[j-1]+f[j])%mod;//预处理前缀和
for(ll j=0;j<=c;++j){
if(j>=i)f[j]=(s[j]-s[j-i]+mod)%mod;
else f[j]=s[j];
}//计算f[j]
}
cout<<f[c];
return 0;
}