今天写个dp的题解,wls的campdiv2 第一个dp
[HAOI2009]逆序对数列
题目描述
对于一个数列 ,如果有 且 ,那么我们称 与 为一对逆序对数。若对于任意一个由 自然数组成的数列,可以很容易求出有多少个逆序对数。那么逆序对数为 的这样自然数数列到底有多少个?
输入格式
第一行为两个整数n,k。
输出格式
写入一个整数,表示符合条件的数列个数,由于这个数可能很大,你只需输出该数对10000求余数后的结果。
样例 #1
样例输入 #1
4 1
样例输出 #1
3
提示
样例说明:
下列3个数列逆序对数都为1;分别是1 2 4 3 ;1 3 2 4 ;2 1 3 4;
测试数据范围
30%的数据 n<=12
100%的数据 n<=1000,k<=1000
分析
这题还是个比较简单的dp,我们考虑状态转移方程含义是所以1到n的全排列,逆序对数量是j的方案数,接着我们就想怎么计算状态,很显然当我们考虑i+1和i的关系就是我们可以把i+1插到原序列的任何一个位置,且插到0,1,2,3...i位置多的逆序对个数分别是i,i-1...0,于是我们可以得出转移方程,在到之间,于是我们可以写出一个的一个时间复杂度,很显然,会tle,但是在洛谷开O2优化可以过。 于是我们开始想怎么优化,很显然要前缀和优化,然后注意一下取模就ok了
代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=1010;
const int mod=10000;
int dp[N][N];
int n,k;
int main(){
cin>>n>>k;
for(int i=0;i<=n;i++) dp[i][0]=1;
for(int i=0;i<n;i++){
for(int j=1;j<=k;j++){
dp[i][j]=(dp[i][j]+dp[i][j-1]+mod)%mod;
if(j-i<=0)
dp[i+1][j]=(dp[i+1][j]+dp[i][j])%mod;
else dp[i+1][j]=(dp[i+1][j]+dp[i][j]-dp[i][j-i-1]+100*mod)%mod;
}
}
cout<<dp[n][k]<<endl;
}