[BZOJ2431][HAOI2009]逆序对数列(DP+前缀和)

来源:互联网 发布:自学唱歌的软件 编辑:程序博客网 时间:2024/04/29 20:01

在这里可以发现,逆序对的个数只与每个数的相对大小有关,而与真实数值无关。根据这一点,建立DP模型:
f[i][j]表示i个不同的数的所有排列中,逆序对数量为j的排列个数。边界为f[1][0]=1
对于转移,可以想到枚举第i个数的排名进行计算,
f[i][j]=jk=ji+1f[i1][k]
在实现上,转移的同时记录下前缀和以快速计算。
代码:

#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;inline int read() {    int res = 0; bool bo = 0; char c;    while (((c = getchar()) < '0' || c > '9') && c != '-');    if (c == '-') bo = 1; else res = c - 48;    while ((c = getchar()) >= '0' && c <= '9')        res = (res << 3) + (res << 1) + (c - 48);    return bo ? ~res + 1 : res;}const int N = 1005, PYZ = 1e4;int n, K, f[N << 1][N << 1], sum[N];int main() {    int i, j; n = read(); K = read();    f[1][0] = sum[1] = 1;    for (j = 2; j <= K + 1; j++) sum[j] = 1;    for (i = 2; i <= n; i++) {        int mxf = min(K, (i * (i - 1)) >> 1);        for (j = 0; j <= mxf; j++)            f[i][j] = (sum[j + 1] -                sum[max(0, j - i + 1)] + PYZ) % PYZ;        sum[0] = 0;        for (j = 0; j <= K; j++)            sum[j + 1] = (sum[j] + f[i][j]) % PYZ;    }    printf("%d\n", f[n][K]);    return 0;}