「COCI 2006-2007 #4」 ZBRKA

题意概括

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

分析

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

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

但是可以发现,第三维就是在找 \([j-i+1,i-1]\) 的区间,所以可以加入一个前缀和,把复杂度优化到 \(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;
}
posted @ 2024-02-23 20:30  run-away  阅读(25)  评论(0)    收藏  举报