【个人心得】简单dp

简单dp这东西主要是看你能不能把状态方程列好,列好之后十分简单,同时这也需要你能意识到题目的意思,一般要算方法数并且后一个状态可以由前一个状态得到,那么一般都是简单dp可以算出来的

说两个题目:

第一个题目链接:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=1496

咋一看这不是数学组的题吗?比赛时没做出来,后来看了题解,原来如此,一个状态转移就行

设一个dp的二维数组,一个代表苹果数,一个代表是否已经吃到大于d的苹果

状态转移方程一共有三个:

1.如果已经吃到大于d的苹果

dp[当前苹果数][已吃到苹果]=(dp[当前苹果数-当前分支苹果数][已吃到苹果]+dp[当前苹果数][已吃到苹果])%mod;

2.没有吃到大于d的苹果,但是现在吃

dp[当前苹果数][已吃到苹果]=(dp[当前苹果数-当前分支苹果数][未吃到苹果]+dp[当前苹果数][已吃到苹果])%mod;

3.没吃到大于d的苹果,也不准备吃

dp[当前苹果数][未吃到苹果]=(dp[当前苹果数-当前分支苹果数][未吃到苹果]+dp[当前苹果数][未吃到苹果])%mod;

代码如下:

​
#include <iostream>
#include <string.h>
#include <string>
#include <algorithm>
#include <stdio.h>
#include <math.h>
#include <stack>
#include <queue>
#include <sstream>
#include <vector>
#include <set>

using namespace std;

const int maxn=200;
const int mod=1e9+7;

int dp[maxn][2];

int main()
{
    int n,k,d;
    while(scanf("%d%d%d",&n,&k,&d)!=EOF)
    {
        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=k&&j<=i;j++)//苹果可以取得的数,正好可以用循环代替
            {
                dp[i][1]=(dp[i-j][1]+dp[i][1])%mod;
                if(j>=d)
                {
                    dp[i][1]=(dp[i-j][0]+dp[i][1])%mod;
                }
                else
                {
                    dp[i][0]=(dp[i-j][0]+dp[i][0])%mod;
                }
            }
        }
        printf("%d\n",dp[n][1]);
    }
    return 0;
}

​

然后知道套路之后立马就A另一道题

题目链接:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=1496

这题有点坑,卡时间,并且还要注意除余后有可能出现的负数

也是三个转移方程,考虑到不能连续跳两次,所以也是两维的数组

第一个代表第几步,第二个代表是否已经跳过,这个自己看代码吧,不多说了

#include <iostream>
#include <string.h>
#include <string>
#include <algorithm>
#include <stdio.h>
#include <math.h>
#include <stack>
#include <queue>
#include <sstream>
#include <vector>
#include <set>

using namespace std;

const int maxn=100005;
const int mod=1e9+7;

int dp[maxn][2],ans[maxn];

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    memset(dp,0,sizeof(dp));
    dp[0][0]=1;
    for(int i=1; i<=maxn; i++)
    {
        if(i>=m)
        {
            dp[i][1]=(dp[i-m][0]+dp[i][1])%mod;
        }
        dp[i][0]=(dp[i-1][0]+dp[i][0])%mod;
        dp[i][0]=(dp[i-1][1]+dp[i][0])%mod;
    }
    ans[0]=0;
    for(int i=1;i<=maxn;i++)
    {
        ans[i]=(ans[i-1]+dp[i][1]+dp[i][0])%mod;
    }
    while(n--)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        if(ans[r]>ans[l-1])
        printf("%d\n",ans[r]-ans[l-1]);
        else
        printf("%d\n",ans[r]+mod-ans[l-1]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/PWeiDa/article/details/82354225