zoukankan      html  css  js  c++  java
  • 【P2401】不等数列(DP)

    这个题乍一看就应该是DP,再看一眼数据范围,1000.。那就应该是了。然后就向DP的方向想,经过对小数据的计算可以得出,如果我们用f[i][j]来表示前i个数有j个是填了"<"的,那么f[i][j]显然可以表示为f[i][j]+=f[i-1][j]*(j+1)+f[i-1][j-1] (i-j).

    至于原因

    1.与f[i-1][j-1]

    在这种情况下,由于我们是从前往后去推的,所以当前加入的数一定比前面的都大。那么怎么才能使得其变为前n个有j个<呢?

    仔细想一下你就会发现,你把这个数插入任何一个数后面,都必将“形成”一个小于号,但是如果我们插入到一个已经形成小于号的两数之间,则小于号数量就不会改变,因为前i-1个数都比当前的i小,所以一共有i-1个空位,但是又有j-1个空位已经形成<号,所以在这种情况下,前i个数形成的每一个有j-1个<的数列都可以形成(i-1)-(j-1)个新的前i个数中有j个<的数列,于是从f[i-1][j-1]能够推出f[i][j]的一部分为f[i-1][j-1]*((i-1)-(j-1))。

    2.与f[i-1][j]

    那么刚刚是说明了你加入这个数增加了一个小于号的情况。但如果我不增加呢?

    我前i-1个数已经形成了j个<。那么我加入i使其不会增加小于号要怎么做呢?

    由于上文我已经说过你把这样的i插入两个之间已经是<号的数之间是不会增加<的数量的。所以这样的空位,每一个形成前i-1数有j个<的数列就有j个这样的空位。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #define re register
    #define ll long long
    #define mo 2015
    using namespace std;
    int n,k,l,f[1001][1001],ans;
    int main()
    {
        cin>>n>>k;
        for(re int i=1;i<=n;i++)
        {
            f[i][i-1]=1;
            f[i][0]=1;
        }
        for(re int i=1;i<=n;i++)
        {
            for(re int j=1;j<i-1;j++)
            {
                f[i][j]+=f[i-1][j]*(j+1)+f[i-1][j-1]*(i-j);
                f[i][j]%=mo;
            }
        }
        cout<<f[n][k]%mo;
    }
  • 相关阅读:
    使用Hibernate Annotations 维护多对多关系
    SpringMVC上传文件以流方式判断类型附常用类型
    Timer 及 TimerTask 相关使用代码
    String与StringBuffer与StringBuilder的区别
    Redis系统性介绍
    利用 psyco 让 Python 程序执行更快
    Linux下安装Metasploit破解Oracle登录用户名密码
    Oracle Database 10g Release 2 下载地址
    yum中找不到包时候解决方式
    Oracle 9.2.0.8 及 10.2.0.4 Patch地址
  • 原文地址:https://www.cnblogs.com/victorique/p/8427047.html
Copyright © 2011-2022 走看看