诸城模拟赛 dvd的逆序对
【题目描述】
dvd是一个爱序列的孩子。
他对序列的热爱以至于他每天都在和序列度过
但是有一个问题他却一直没能解决
给你n,k求1~n有多少排列有恰好k个逆序对
【输入格式】
一行两个整数n,k
【输出格式】
输出一个整数,表示答案对1000000007取模后的结果
【样例输入】
4 1
【样例输出】
3
【样例解释】
1 2 4 3
1 3 2 4
2 1 3 4
【数据规模及约定】
对于10%的数据 n<=10
对于30%的数据 k<=50
对于100%的数据 1<=n,k<=1000 且 k<=n*(n-1)/2
/* 当年的爆零题,今年的一眼题 我们可以注意到,题目中要求的是这个方案数,而且这个数字很大,要对一个很大的数取模,考虑dp,f[i][j]表示1~j的排列恰好有i个逆序对,考虑f[i][j+1],等于是多了一个数字j+1,包括这个数字的逆序对是他后面的数的个数,剩下的逆序对就又前面j的排列来填补,这样维护一个前缀和,f[i][j] = f[i-j+1……i][j-1] */ #include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> using namespace std; const int maxn = 1050; const int mod = 1000000007; int n,k,f[maxn][maxn],s[maxn][maxn]; int main(){ freopen("sequence.in","r",stdin); freopen("sequence.out","w",stdout); cin>>n>>k; for(int i = 1;i <= n;i++) s[0][i] = f[0][i] = 1; for(int i = 1;i <= k;i++){ for(int j = 1;j <= n;j++){ if(i >= j)f[i][j] = (s[i][j-1] - s[i-j][j-1] + mod) % mod; else f[i][j] = s[i][j-1]; s[i][j] = (s[i-1][j] + f[i][j]) % mod; } } cout<<f[k][n]<<endl; return 0; }