51NOD 1296-dp

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1296

题意就是一个 1--n 的序列,然后给你一些数,要再这些位置比旁边大,另一些数,这些位置要比旁边的小。。

题意就是这样,之前做的题拿出来复习。。

dp思路是 dp[i][j]  表示 前i个数最后一位是j是什么的时候有多少可行方案(是不是有点像数位dp的思路。。。)

做一个标记来标记每一位和前一位的大小关系。

那么分三种情况考虑一下:

第i位一是个普通位  ,那么dp[i][j]就是dp[i-1][1~(i-1)]所有的答案和,为什么呢,因为可以看做把前面的每一种安排比j大的都加1就好了。。这样也不影响原来的合法性

第i位 要比前一位低,那么明显不能都加1 了,因为不一定满足第i位合法了,所以其实保证第i-1位大于等于j,也就是dp[i-1][j~(i-1)]所有答案的和,

第i位 要比前一位高, 同理,就是dp[i-1][1~j-1]所有答案的和,

由于上面的转移方法,所以我们再加一个辅助的前缀和数组就可以了。

代码如下:

#include <iostream>
#include <vector>
#include <cstring>
#include <cstdio>
using namespace std;

int dp[5001][5001];
int sum[5001];
int a[5001];
int b[5001];
int n,na,nb;
int ans;
const int mo=1e9+7;

void DP(){
    ans=0;
    memset(dp,0,sizeof(dp));
    dp[1][1]=1;
    sum[1]=1;
    for(int i=2;i<=n;i++){
        for(int j=1;j<=i;j++){
            if(a[i]==1){
                dp[i][j]=sum[j-1];
            }
            else if(a[i]==-1){
                dp[i][j]=(sum[i-1]-sum[j-1]+mo)%mo;
            }
            else{
                dp[i][j]=sum[i-1];
            }
        }
        for(int j=1;j<=i;j++){
            sum[j]=((long long)sum[j-1]+dp[i][j])%mo;
        }
    }
    for(int i=1;i<=n;i++){
        ans=(ans+dp[n][i])%mo;
    }
    cout<<ans%mo<<endl;
}
int main()
{
    while(cin>>n>>na>>nb){
        int x;
        for(int i=0;i<na;i++){
            scanf("%d",&x);
            ++x;
            a[x]=1;
            a[x+1]=-1;
        }
        memset(b,0,sizeof(b));
        for(int i=0;i<nb;i++){
            scanf("%d",&x);
            ++x;
            a[x]=-1;
            a[x+1]=1;
        }
        DP();
    }
    return 0;
}
时间: 2024-11-13 06:46:32

51NOD 1296-dp的相关文章

51nod 1296 有限制的排列(DP)

对于一个i,如果要比邻居大,那么i比i-1大,i+1比i小,比邻居小同理.设v[i]=0表示i与i-1的关系无限制,v[i]=1表示a[i-1]>a[i],v[i]=2表示a[i-1]<a[i] 则有 显然这个是可以用前缀和优化成O(N^2)的 #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #define MOD(x) (x>=mod?x-mo

51nod 1154 dp

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1154 1154 回文串划分 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 收藏 关注 有一个字符串S,求S最少可以被划分为多少个回文串. 例如:abbaabaa,有多种划分方式. a|bb|aabaa - 3 个回文串 a|bb|a|aba|a - 5 个回文串 a|b|b|a|a|b|a|a - 8 个回文串 其中第1种划分方式的

51nod 1270 dp

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1270 简单的线性dp,最近狂刷水题真的是...药丸 差值最大得话要么是峰顶要么是最小的1,不可能处在中间状态,那样显然没有峰值的贡献大,想通这一点之后方程就好写了, dp[i][0]表示第i个数取最小值的最大代价,dp[i][1]相反. 有 dp[i][0]=max(dp[i-1][0],dp[i-1][1]+a[i-1]-1); dp[i][1]=max(dp[i-1

[51nod]A树的双直径

题目链接: 51nod 树形\(DP\)+换根\(DP\). 最直观的想法是枚举一条边断开,在两颗子树中求最大直径相乘然后取最大值. 不过这题可能出现负数,那么答案可能是正数\(\times\)正数或者负数\(\times\)负数. 其实只需要考虑正数的情况(负数把边全部取反即可) 那么设枚举边\((x,y)\),其中\(x\)为\(y\)的父亲 那么我们需要求出以\(y\)为根子树中的最长链和除去\(x\)子树外的最长链 对于\(y\)子树中的最长链\(InMax[y]\),我们可以先考虑求出

51nod 1201 整数划分(dp)

题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1201 题解:显然是一道dp,不妨设dp[i][j]表示数字i分成j个一共有几种分法. 那么转移方程式为: dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1] 表示将i - 1划分为j个数,然后j个数都+1 还是不重复,将i - 1划分为j - 1个数,然后j - 1个数都+1,再加上1这个数. 然后就是j的范围要知道1+2+

51nod 1406 位运算/dp

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1406 1406 与查询 题目来源: CodeForces 基准时间限制:2 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 收藏 关注 有n个整数.输出他之中和x相与之后结果为x的有多少个.x从0到1,000,000 Input 第一行输入一个整数n.(1<=n<=1,000,000). 第二行有n个整数a[0],a[1],a[2],...a[n-1

51nod 1412 AVL树的种类(经典dp)

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1412 题意: 思路: 经典dp!!!可惜我想不到!! $dp[i][k]$表示i个结点,最大深度为k的形态数. 它的转移方程就是: dp[i][k] += dp[i - 1 - j][k - 1] * dp[j][k - 1] dp[i][k] += 2 * dp[i - 1 - j][k - 2] * dp[j][k - 1] j是右子树结点个数,如果除去根结点,是不

51NOD 1202 子序列个数 DP

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1202&judgeId=225600 这题看起来挺复杂,但是真正的dp还是挺好理解的.唯独是想不到的,应该把样例模拟一遍. 比如1.2.4.2 考虑第一个,只有"1"这一个子序列 考虑前两个,有:"1", "12", "2" 前三个,有:"1", "12"

51nod 1043 幸运号码(数位dp)

题目链接:51nod 1043 幸运号码 题解:dp[i][j]表示 i 个数和为 j 的总数(包含0开头情况) dp[i][j] = dp[i-1][j-k] i & 1 :这里用滚动数组节省内存 非0开头的情况 * 0开头的情况:(dp[n&1][i]-dp[(n-1)&1][i]) *dp[n&1][i],最后将其累加即为结果. 1 #include<cstdio> 2 #include<algorithm> 3 #include<cst

51Nod 1083 矩阵取数问题(矩阵取数dp,基础题)

1083 矩阵取数问题 基准时间限制:1 秒 空间限制:131072 KB 分值: 5 难度:1级算法题 一个N*N矩阵中有不同的正整数,经过这个格子,就能获得相应价值的奖励,从左上走到右下,只能向下向右走,求能够获得的最大价值. 例如:3 * 3的方格. 1 3 3 2 1 3 2 2 1 能够获得的最大价值为:11. Input 第1行:N,N为矩阵的大小.(2 <= N <= 500) 第2 - N + 1行:每行N个数,中间用空格隔开,对应格子中奖励的价值.(1 <= N[i]