codeforces 413D 2048 (dp)

本文详细介绍了如何通过动态规划解决2048游戏的简化版问题,即在一维数组中,计算满足和大于给定阈值k的方案数。通过分析数据特点和设计算法,实现高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

这是个2048游戏的简化版,只有一行,如果有两个位置的值相等那么就相加,知道不能加为止,题目给出n个数只有三种情况0、2、4, 0表示可以是2也可以是4。问给出的n个数中满足和大于k的方案数。

题解:

一眼看过去方程很快出来,看似很简单但是很难。因为有这样数据8422,2242222,这样的话中间有组个不能相加,那么要处理后面如果后面的加起来等于前面的于是又可以相加。看到这种数据的确想不到什么好办法。

大牛正解


#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;
const int oo=0x3f3f3f3f;
const ll OO=1LL<<61;
const ll MOD=1000000007;
const int maxn=2005;
const int maxm=2050;
ll dp[maxn][maxm][2];
int a[maxn];

int main()
{
    int n,k;
    while(scanf("%d %d",&n,&k)!=EOF)
    {
        memset(dp,0,sizeof dp);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        dp[0][0][0]=1;
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<maxm;j++)
            {
                int p;
                if(a[i]==0||a[i]==2)
                {
                    p=min(j+2,2048);
                    dp[i][p][0]=(dp[i][p][0]+dp[i-1][j][0]+MOD)%MOD;
                    dp[i][p][1]=(dp[i][p][1]+dp[i-1][j][1]+MOD)%MOD;
                }
                if(a[i]==0||a[i]==4)
                {
                    if(j%4)
                    {
                        if(j>=(1<<k))///这步非常关键!!
                            dp[i][4][1]=(dp[i][4][1]+dp[i-1][j][0]+MOD)%MOD;
                        else
                            dp[i][4][0]=(dp[i][4][0]+dp[i-1][j][0]+MOD)%MOD;
                        dp[i][4][1]=(dp[i][4][1]+dp[i-1][j][1]+MOD)%MOD;
                    }
                    else
                    {
                        p=min(j+4,2048);
                        dp[i][p][0]=(dp[i][p][0]+dp[i-1][j][0]+MOD)%MOD;
                        dp[i][p][1]=(dp[i][p][1]+dp[i-1][j][1]+MOD)%MOD;
                    }
                }
            }
        }
        ll ans=0;
        for(int i=0;i<maxm;i++)
        {
            ans=(ans+dp[n][i][1]+MOD)%MOD;
            if(i>=(1<<k))
                ans=(ans+dp[n][i][0]+MOD)%MOD;
        }
        cout<<ans<<endl;
    }
    return 0;
}
/**
0 2 2
1 0 100
1 2 0
3

*/



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值