P2513 [HAOI2009]逆序对数列

题意:

求1-n的排列中逆序对数为k的排列个数

 

首先20分暴力next_permutation  qaq

正解:DP

   以f[i][j]表示1-i的排列有j个逆序对的方案、

   考虑转移:对于新来的i

        肯定是由i-1转移过来的

        那么因为是排列,i一定比1--i-1都大

        所以考虑它插入的位置

        比如1 2 3 4 现在要插入5

        产生逆序对的个数等于插入位置后面的数的个数

        所以,它的加入对答案的贡献是$\in (0,i-1)$的

        因此,$f[i][j]=\sum_{p=0}^{i-1}f[i][j-p]$        

   可以用前缀和优化,sum记录j-i+1到j的f之和

   随着j的增加,在加上当前的同时别忘了减去开头(sum的长度固定,为i-1)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cctype>
#include<algorithm>
using namespace std;
#define int long long
#define olinr return
#define _ 0
#define love_nmr 0
#define DB double
#define mod 10000
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            f=-f;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
inline void put(int x)
{
    if(x<0)
    {
        x=-x;
        putchar('-');
    }
    if(x>9)
        put(x/10);
    putchar(x%10+'0');
}
int f[105][10500];
int n;
int k;
int ans;
signed main()
{
    n=read();
    k=read();
    for(int i=1;i<=n;i++)
        f[i][0]=1;
    for(int i=2;i<=n;i++)
    {
        int tot=0;
        for(int j=0;j<=k;j++)
        {
            (tot+=f[i-1][j])%=mod;
            f[i][j]=tot%mod;
            if(j-i+1>=0)
                (((tot-=f[i-1][j-i+1])+=mod)%=mod);
        }
    }
    put(f[n][k]%mod);
    olinr ~~(0^_^0)+love_nmr;
}

 

posted @ 2018-09-02 10:50  olinr  阅读(232)  评论(0编辑  收藏  举报