description
求出满足逆序对个数不大于(k)的(n)的排列个数.
solution
挺水的一道签到题,但忘取模20pts滚粗(cdots)
首先我们定义(f[i][j])表示(i)的排列中逆序对个数为(j-1)的数量,根据打表找规律可知,(f[i][j]=f[i-1][j]+f[i][j-1],j<=i);(f[i][j]=f[i-1][j]+f[i][j-1]-f[i-1][j-frac{(i-1)cdot (i-2)}{2}],j>i),预处理出(f[1][1]=1),于是乎,(Omicron(ncdot k))复杂度算法就此诞生.另外,为了满足空间限制,我们需要开滚动数组滚掉第一维.
code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#define R register
#define next kdjadskfj
#define debug puts("mlg")
#define mod 10000000007
#define Mod(x) ((x%mod+mod)%mod)
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
inline ll read();
inline void write(ll x);
inline void writeln(ll x);
inline void writesp(ll x);
ll n,k;
ll f[2][3100];
ll res=0;
int main(){
freopen("matryoshka.in","r",stdin);
freopen("matryoshka.out","w",stdout);
n=read();k=read();
f[1][1]=1;
for(R ll i=2;i<=n;i++){
ll r=min(k+1,((i*(i-1))>>1)+1);
for(R ll j=1;j<=r;j++){
if(j<=i) f[i&1][j]=Mod(f[(i&1)^1][j]+f[i&1][j-1]);
else f[i&1][j]=Mod(f[i&1][j-1]+f[(i&1)^1][j]-f[(i&1)^1][j-i]);
}
}
for(R ll i=1;i<=min(k+1,(((n*(n-1))>>1)+1));i++) res=Mod(res+f[n&1][i]);
writeln(res);
}
inline ll read(){ll x=0,t=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') t=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*t;}
inline void write(ll x){if(x<0){putchar('-');x=-x;}if(x<=9){putchar(x+'0');return;}write(x/10);putchar(x%10+'0');}
inline void writesp(ll x){write(x);putchar(' ');}
inline void writeln(ll x){write(x);putchar('
');}