Logo lxn 的博客

博客

P2513 [HAOI2009] 逆序对数列

...
lxn
2025-12-01 12:57:48

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2025-01-16 09:22:53

题目分析

设$f[i][j]$为用了前i个数产生j个逆序对的方案数。

$ f[i][j]=\sum_{j-i+1}^k f[i-1][k] $ 这是一段连续的数值,可以用区间和优化。

参考代码

#include <iostream>
#include <cstdio>
using namespace std;
int n,k;
const int p=10000;
int f[2000][2000],s[2000][2000];
int main() {
    scanf("%d%d",&n,&k);
    f[1][0]=1;
    for(int i=0;i<=k;i++)s[1][i]=1;
    for(int i=2;i<=n;i++){
	
        for(int j=0;j<=k;j++) {
            if(j>=i)f[i][j]=(s[i-1][j]-s[i-1][j-i])%p;
            else f[i][j]=s[i-1][j];
       		if(j>=1)s[i][j]=(s[i][j-1]+f[i][j])%p;
       		else s[i][j]=f[i][j];
        }
      
   }

    printf("%d\n",(f[n][k]+p)%p);
    return 0;
}

滚动数组优化

本题的第$i$行只与$i-1$行相关。

参考代码

#include <iostream>
#include <cstdio>
using namespace std;
int n,k;
const int p=10000;
int f[2][2000],s[2][2000];
int main() {
    scanf("%d%d",&n,&k);
    f[1][0]=1;
    for(int i=0;i<=k;i++)s[1][i]=1;
    for(int i=2;i<=n;i++){
        for(int j=0;j<=k;j++) {
            if(j>=i)f[i&1][j]=(s[(i-1)&1][j]-s[(i-1)&1][j-i])%p;
            else f[i&1][j]=s[(i-1)&1][j];
       		if(j>=1)s[i&1][j]=(s[i&1][j-1]+f[i&1][j])%p;
       		else s[i&1][j]=f[i&1][j];
         
        }
      
	}

    printf("%d\n",(f[n&1][k]+p)%p);
    return 0;
}

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。