zoukankan      html  css  js  c++  java
  • NKOJ P3051浇花

    时间限制 : 10000 MS   空间限制 : 65536 KB
    问题描述

    n 个非负整数排成一行,每个数值为Ai,数的位置不可改变。需要把所有的数都恰好等于h。可进行的操作是:对任意长度的区间[i,j]中的每个数都加1,i 和j 也任选,但要求每个数只能作为一次区间的起点,也只能作为一次区间的终点。 也即是说: 对任意的两个区间[l1, r1] 和[l2, r2], 要求: l1≠l2 并且r1 ≠ r2.
    请问有多少种不同的方式,使所有的数都等于h.输出答案模1000000007 (10^9+7)后的余数。
    两种方式被认为不同,只要两种方式所实施的操作的区间集合中,有一个区间不同即可.

    输入格式

    第1 行:2 个整数n, h (1 ≤ n, h ≤ 2000)
    接下来n 行,每行1 个整数,表示Ai (1≤Ai≤2000)
    30%的数据,n, h <= 30
    100%的数据,n, h <= 2000

    输出格式

    第1 行:1 个整数,表示答案

    样例输入

    Sample1:
    3 2
    1 1 1
    Sample2:
    5 1
    1 1 1 1 1

    样例输出

    Sample1:
    4
    Sample2:
    1

    浇花
    考点 区间动态规划
    类似于括号 dp 的讨论方式,讨论 i 的左边,选哪个数字作为区间的起点,更新 i 的值
    dp[i][k]表示从左往右讨论到第 i 个数字,i 的左边有 k 个数字还未被用过(被当做区间的左
    起点), 的方案数。
    分两种情况讨论:
    情况 1:i 被别人更新(因为 i 前面的 k 个数,任选一个为区间起点,都可更新到 i):
    若 a[i]+k==h 则 dp[i][k]=dp[i+1][k-1]*k+dp[i+1][k]
    说明,条件 a[i]+k==h,因为 i 左边有 k 个数字还没用过,那么以这 k 个数字作为区间左起点可以操作 k 次,每次都可以更新到 i,更新 k 次,恰好就能使 a[i]变成 h。
    现在对于 i 而言,有两种选择, 使用 i 或者不使用 i。
    若用 i 作为区间右端点,因为 i 只能当一次区间终点,所以只能从前 k 个中选一个来与
    它配对,故有 k 种方案,k 个数中 i 选了一个,对于 i+1 它左边就只有 k-1 个未使用的数了,数
    量总数为 k*dp[i+1][k-1] 。
    注意,这里 i 不能再作为区间的左端点了,这样的话会导致 i 被多更新一次,高度变成
    h+1
    若不用 i 作为区间端点,则方案数为 dp[i+1][k]
    情况 2:i 作为区间起点去更新别人
    若 a[i]+k+1=h 则 dp[i][k]=dp[i+1][k]*(k+1)+dp[i+1][k+1]
    说明,因为 i 前面有 k 个数未被当做左起点使用,全部操作都只能把 a[i]更新到 h-1 这个
    高度,那么 i 号点必须自己作为某区间的左起点更新一次,在更新这个区间的同时把自己的高
    度也更新 1,达到 h。
    这样,对于下一个数 i+1 而言,算上 i 号点,它左侧有 k+1 个点可选做区间左端点,任
    选一个选后剩下 k 个点,状态 dp[i+1][k]
    若不用 i 作为区间左端点,则方案数为 dp[i+1][k+1]
    时间复杂度 O(n
    2
    ),实现时采用记忆化搜索比较方便。
     
     
     
    code;
    //
    #include<bits/stdc++.h>
    #define mod 1000000007
    using namespace std;
    #define ll long long 
    ll n,h;
    ll f[4001][4001];
    ll a[4002];
    ll  dfs(ll i,ll k)
    {
        if(f[i][k]) return f[i][k];
        {
            if(i==n+1&&k>0)
            return 0;
            if(k+a[i]==h)
                 {
                     f[i][k]=dfs(i+1,k-1)*k%mod+dfs(i+1,k)%mod;
                 }
                 if(k+a[i]+1==h)
                 {
                     f[i][k]=dfs(i+1,k)*(k+1)%mod+dfs(i+1,k+1)%mod;
                 }
        }
        return f[i][k]%mod;
        
    }
    int main()
    {
        cin>>n>>h;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
         } 
         f[n+1][0]=1;
        cout<<dfs(1,0)%mod;
        
    }

     认真看题 DP 方程自题出!!!


     
    刀剑映出了战士的心。而我的心,漆黑且残破
  • 相关阅读:
    开放源码的对象关系映射工具ORM.NET 插入数据 Insert/Update Data
    开放源码的对象关系映射工具ORM.NET 快档开发入门 Quick Start
    .NET 动态脚本语言Script.NET 开发指南
    开放源码的对象关系映射工具ORM.NET 删除数据 Deleting Records using ORM.NET
    .NET Remoting过时了吗?为什么公司的项目还是选择用.NET Remoting,而不是WCF?
    开放源码的对象关系映射工具ORM.NET 查看和显示数据 View and Display data using ORM.NET
    开放源码的对象关系映射工具ORM.NET 查询表 调用存储过程 增加自定义代码
    技术人生:坚持,每日一博
    CQRS:CQRS + DDD + MDP 实现快速应用程序开发
    NodeJs:Happy代码生成器,重构了代码,更新了文档,完善了示例,欢迎下载使用
  • 原文地址:https://www.cnblogs.com/OIEREDSION/p/11210858.html
Copyright © 2011-2022 走看看