[HAOI2009] 逆序对数列

观察数据范围我们发现可以用DP来做这个题qwq,因为它每一位往上填的时候,无论怎么填,总可以从前面的状态转移过来。

而且题目保证了是从1-n的自然数,所以不存在相同数字的情况。

我们设计状态\(dp[i][j]\)为长度为i的序列(也就是前\(i\)个自然数)排成的序列中逆序对数量为\(j\)的答案个数。

之后的转移就是往原先的序列中塞下一个数,填的位置不同自然增加的逆序对数量不一样,但是显然增加的数量只能在\(0\)\({i-1}\)中。

首先我们可以考虑暴力的\(n^3\)做法。

转移方程:
\[dp[i][j]=\sum_{k=0}^{max(j-i+1,0)}dp[i-1][k]\]

试了试竟然有90分???

但是显然1000的数据不是让我们用\(n^3\)闹着玩的。所以我们要试图将它优化到\(n^2\)。这个优化很容易,打个表我们稍加思考就可以发现,每次加的数有重复,而且是以前缀和的形式出现的。所以我们直接记录前缀和做优化就可以省略掉k的遍历了。

\(sum[i][j]\)来记录前i个数前j个逆序的答案个数。。。。就行了吧qwq

代码如下。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define mod 10000
using namespace std;
int n,k;
int dp[1010][1010],sum[1010][1010];
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=0;i<=n;i++) dp[i][0]=1,sum[i][0]=1;
    sum[0][0]=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=k;j++)
        {
            dp[i][j]=(dp[i][j]+sum[i-1][j])%mod;
            if(j-i>=0) dp[i][j]=(dp[i][j]+mod-sum[i-1][j-i])%mod;
            sum[i][j]=(sum[i][j-1]+dp[i][j])%mod;
        }
    }
    printf("%d\n",dp[n][k]);
    return 0;
} 

转载于:https://www.cnblogs.com/fengxunling/p/9834917.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值