持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第31天,点击查看活动详情
求逆序对
题目描述
我们说(i,j)是a1,a2,…,aN的一个逆序对当且仅当i<j且ai>a j。例如2,4,1,3,5的逆序对有3个,分别为(1,3),(2,3),(2,4)。现在已知N和K,求1…N的所有特定排列,这些排列的逆序对的数量恰好为K。输出这些特定排列的数量。
例如N=5,K=3的时候,满足条件的排列有15个,它们是:
1,2,5,4,3
1,3,4,5,2
1,3,5,2,4
1,4,2,5,3
1,4,3,2,5
1,5,2,3,4
2,1,4,5,3
2,1,5,3,4
2,3,1,5,4
2,3,4,1,5
2,4,1,3,5
3,1,2,5,4
3,1,4,2,5
3,2,1,4,5
4,1,2,3,5
输入格式
输入第一行有两个整数N和K。(N≤100,K≤N*(N-1)/2)
输出格式
将1…N的逆序对数量为K的特定排列的数量输出。为了避免高精度计算,请将结果mod 10000以后再输出!
样例 #1
样例输入 #1
5 3
样例输出 #1
15
解题思路
dp 方程很容易得出:f[i][j]=f[i-1][j-i+1]+f[i-1][j-i+2]+……+f[i-1][j]
时间复杂度:O(n^3)
但可以优化为O(n^2)
因为f[i][j]=f[i-1][j-i+1]+f[i-1][j-i+2]+……+f[i-1][j]
f[i][j-1]=f[i-1][j-i]+f[i-1][j-i+1]+f[i-][j-i+2]+……+f[i-1][j-1]
这两个式子有许多重复项
所以可以合并为f[i][j]=f[i][j-1]+f[i-1][j]-f[i-1][j-i]
#include<bits/stdc++.h>
using namespace std;
int n,k,dp[105],f[105][5000];
int main(){
cin>>n>>k;
f[0][0]=f[1][0]=1;
for(int i=2;i<=n;i++){
dp[i]=dp[i-1]+i-1;
for(int j=0;j<=dp[i];j++){
f[i-1][j]%=10000;
if(j<=dp[i]/2){
f[i][j]=f[i-1][j]+f[i][j-1];
if(j>=i)f[i][j]-=f[i-1][j-i];
}
else f[i][j]=f[i][dp[i]-j];
}
}
cout<<f[n][k]%10000;
return 0;
}