「COCI 2006-2007」 ZBRKA

文章讲述了如何通过观察问题特性,利用前缀和将计算逆序对的动态规划算法复杂度从O(n*c^2)降低到O(n*c),并通过C++代码实现这一优化过程。

题意概括

题面很清楚,不多赘述了。

分析

fi,jf_{i,j}fi,j 表示已用前 iii 个数,使数列出现 jjj 个逆序对的方案数。

因为从小到大枚举 iii,所以填 iii 时前面所有的数都比它小,那么 iii 每向前移动一位,就会增加一个逆序对。所以可以直接枚举每一个 i,ji,ji,j,再枚举插入 iii 的位置,转移方程是 fi,j=∑k=0i−1fi−1,j−kf_{i,j}=\sum\limits_{k=0}^{i-1} f_{i-1,j-k}fi,j=k=0i1fi1,jk。但这样是 O(nc2)O(nc^2)O(nc2) 的,会 TLE

但是可以发现,第三维就是在找 [j−i+1,i−1][j-i+1,i-1][ji+1,i1] 的区间,所以可以加入一个前缀和,把复杂度优化到 O(nc)O(nc)O(nc),通过这道题。

Code

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const ll mod=1e9+7;
ll n,c,f[10005]={1},s[10005];
signed main(){
    cin>>n>>c;
    for(ll i=2;i<=n;++i){
        s[0]=f[0];
        for(ll j=1;j<=c;++j)s[j]=(s[j-1]+f[j])%mod;//预处理前缀和
        for(ll j=0;j<=c;++j){
            if(j>=i)f[j]=(s[j]-s[j-i]+mod)%mod;
            else f[j]=s[j];
        }//计算f[j]
    }
    cout<<f[c];
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值