Loading [MathJax]/jax/element/mml/optable/BasicLatin.js

luogu2513 逆序对数列

我们令f[i][j]表示i的全排列中,逆序数为j的个数。

我们考虑在i1的排列中插入ik是这次更新会导致增加多少逆序数。

f[i][j]=k=0min

自我感觉上面的写法不清真,所以换一个清真的等价写法。

\begin{aligned}{} f[i][j]=\sum_{k=max(0,j-i+1)}^{j}f[i-1][k]\end{aligned}

复杂度:O(nk^2),显然会tle。

我们观察这个式子,k是从0开始循环的,所以我们用前缀和优化dp。

我们开一个变量\begin{aligned}sum=\sum_{k=max(0,j-i+1)}^jf[i][k]\end{aligned}

每次j循环的时候让,把f[i-1][j]累加到sum,然后让f[i][j]=sum即可

sum的求和区间是长度为i的一段f数组,当j-i+1>=0的时候sum求和区间的左端点也要离开0,向右移动了,所以加一个右面的f[i-1][j],同时要判断sum的左端点是否大于0,如果是那么就减去左边的f[i-1][j-i+1]。(不理解?看下面)

欢迎收看新番:区间先生的旅程
这是我们的主人公[---]:区间先生,长度为5
[---]说他只是一个走过场的区间
t=0, ................
t=1, ]...............
t=2, -]..............
t=3, --].............
t=4, ---]............
t=5, [---]...........
t=6, .[---]..........//注意这里,区间先生的左端点脱离了0
t=7, ..[---].........//未完待续???
...
t=?, ...........[---]//因为我们只需要求到k,所以区间先生不用从右端离开,也就不用判断右端是否<=k了

这就是为什么要加一个if判断一下。

其实这个if可以放到前面的额不过懒得写了

复杂度:O(nk)

总结:以后我们发现有这种累加和的dp方程的时候可以考虑前缀和优化

代码

#include <cstdio>
#include <iostream>

using namespace std;

int n, k, p = 10000, f[1010][1010];

int main()
{
    scanf("%d%d", &n, &k);
    f[1][0] = 1;//初始条件,1的逆序为0,且只有1个排列
    for (int i = 2; i <= n; i++)
    {
        int sum = 0;
        for (int j = 0; j <= k; j++)
        {
            (sum += f[i - 1][j]) %= p;
            f[i][j] = sum;
            if(j >= i - 1)//如果j - i + 1>=0了,sum的求和区间左端点就>=0
                (((sum -= f[i - 1][j - i + 1]) %= p)+= p) %= p;
        }
    }
    printf("%d\n", f[n][k]);
    return 0;
}

posted @   ghj1222  阅读(137)  评论(0编辑  收藏  举报
编辑推荐:
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
· .NET 适配 HarmonyOS 进展
阅读排行:
· 如何给本地部署的DeepSeek投喂数据,让他更懂你
· 超详细,DeepSeek 接入PyCharm实现AI编程!(支持本地部署DeepSeek及官方Dee
· 用 DeepSeek 给对象做个网站,她一定感动坏了
· .NET 8.0 + Linux 香橙派,实现高效的 IoT 数据采集与控制解决方案
· .NET中 泛型 + 依赖注入 的实现与应用
点击右上角即可分享
微信分享提示