「COCI 2006-2007」 ZBRKA

题意概括

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

分析

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

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

但是可以发现,第三维就是在找 [ j − i + 1 , i − 1 ] [j-i+1,i-1] [ji+1,i1] 的区间,所以可以加入一个前缀和,把复杂度优化到 O ( n c ) 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、付费专栏及课程。

余额充值