[luogu2513 HAOI2009] 逆序对数列 (计数dp)

题目描述

对于一个数列{ai},如果有i

输入输出格式

输入格式:
第一行为两个整数n,k。

输出格式:
写入一个整数,表示符合条件的数列个数,由于这个数可能很大,你只需输出该数对10000求余数后的结果。

输入输出样例

输入样例#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

f[i][j] 表示i的排列有j个逆序对数的情况数
依次插入1,2,3,4......,n
插入第i个数时:
当插在0位置时逆序对增加(i-1)组,
当插在1位置时逆序对增加(i-2)组,
......
跟据以上想法推出出动规方程:

F(i,1,n) F(j,1,k) F(l,max(1,i-j),i) 
    f[i][j]+=f[i-1][j-(i-l)];

n^3过不了,用下前缀和优化即可
code:

//By Menteur_Hxy
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <vector>
#include <queue>
#include <set>
#include <ctime>
#define M(a,b) memset(a,(b),sizeof(a))
#define F(i,a,b) for(register int i=(a);i<=(b);i++)
#define LL long long
using namespace std;

inline LL rd() {
    LL x=0,fla=1; char c=' ';
    while(c>'9'|| c<'0') {if(c=='-') fla=-fla; c=getchar();}
    while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
    return x*fla;
}

inline void out(LL x){
    int a[25],wei=0;
    if(x<0) putchar('-'),x=-x;
    for(;x;x/=10) a[++wei]=x%10;
    if(wei==0){ puts("0"); return;}
    for(int j=wei;j>=1;--j) putchar('0'+a[j]);
    putchar('\n');
}

const int MOD=10000;
const int N=1010;
const int INF=0x3f3f3f3f;
int n,k;
int f[N][N];

int main() {
    n=rd(),k=rd();
    f[1][0]=1;
    F(i,2,n) {
        LL sum=0;
        F(j,0,k) {
            (sum+=f[i-1][j])%MOD;
            f[i][j]=sum%MOD;
            if(j-i+1>=0) ((sum-=f[i-1][j-i+1])+MOD)%MOD;
        }
    } 
    out(f[n][k]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Menteur-Hxy/p/9139398.html
今日推荐