模板积累——数位DP

本文介绍了一种用于判断一个数字是否为13的倍数的递归算法。通过动态规划的方式,算法考虑了数字的每一位及其对13取模的结果,同时标记数字的特定状态,如末尾是否为1或包含13。此算法适用于处理大数字,并在不超出计算资源限制的情况下返回结果。

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

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

int bit[15];
int dp[15][15][3];
//dp[i][j][k]
//i:数位
//j:余数
//k:3种操作状况,0:末尾不是1,1:末尾是1,2:含有13

int dfs(int pos,int mod,int pre,int lim)//lim记录上限
{
    int num,i,ans,mod_x,pre_x;
    if(pos<=0)
        return mod == 0 && pre == 2;
    if(!lim && dp[pos][mod][pre] != -1)//没有上限并且已被访问过
        return dp[pos][mod][pre];
    num = lim?bit[pos]:9;//假设该位是2,下一位是3,如果现在算到该位为1,那么下一位是能取到9的,如果该位为2,下一位只能取到3
    ans = 0;
    for(i = 0; i<=num; i++)
    {
        mod_x = (mod*10+i)%13;//看是否能整除13,而且由于是从原来数字最高位开始算,细心的同学可以发现,事实上这个过程就是一个除法过程
        pre_x = pre;
        if(pre == 0 && i == 1)//末尾不是1,现在加入的是1
            pre_x = 1;//标记为末尾是1
        if(pre == 1 && i != 1)//末尾是1,现在加入的不是1
            pre_x = 0;//标记为末尾不是1
        if(pre == 1 && i == 3)//末尾是1,现在加入的是3
            pre_x = 2;//标记为含有13
        ans+=dfs(pos-1,mod_x,pre_x,lim&&i==num);//lim&&i==num,在最开始,取出的num是最高位,所以如果i比num小,那么i的下一位都可以到达9,而i==num了,最大能到达的就只有,bit[pos-1]
    }
    if(!lim)
        dp[pos][mod][pre] = ans;
    return ans;
}

int main()
{
    int n,len;
    while(~scanf("%d",&n))
    {
        memset(bit,0,sizeof(bit));
        memset(dp,-1,sizeof(dp));
        len = 0;
        while(n)
        {
            bit[++len] = n%10;
            n/=10;
        }
        printf("%d\n",dfs(len,0,0,1));
    }

    return 0;
}
### 问题重述 有一串石头,共 `n` 个(`n <= 100`),石头有 `k` 种颜色(`k <= 5`)。我们需要拿走其中的一些石头,使得剩下的石头中,**同种颜色的石头都连续地排列在一起**。求需要拿走的石头数量的最小值。 换句话说,我们需要找到一种方式,通过移除最少数量的石头,使得剩下的石头序列中,所有相同颜色的石头都是连续的一段。 ### 示例 假设石头序列和颜色如下(用字母表示颜色): ``` A B A C B ``` - 移除第2个石头 `B` 和第4个石头 `C`,剩下 `A A B`,满足条件(`A`连续,`B`连续)。 - 共移除2个石头,是最小值。 ### 解题思路 这是一个典型的**动态规划(DP)**问题,结合**状态压缩**的思想。由于 `k` 很小(`k <= 5`),我们可以用**状态压缩**来表示当前已经处理了哪些颜色。 #### 关键观察 1. **最终序列的性质**:剩下的石头序列一定是若干段连续的同色石头组成,且**每种颜色最多出现一段**。例如,`A A B B C C` 或 `A A C C B B` 等。 2. **状态定义**:我们可以用 DP 状态 `dp[mask][last_color]` 表示: - `mask`:一个 `k` 位的二进制数,表示已经处理了哪些颜色(`1` 表示已处理,`0`表示未处理)。 - `last_color`:最后一段石头的颜色。 - `dp[mask][last_color]` 的值:在 `mask` 和 `last_color` 的限制下,**保留的石头数量的最大值**(这样移除的石头数量就是 `n - dp[mask][last_color]`)。 3. **状态转移**: - 对于当前状态 `(mask, last_color)`,我们可以尝试扩展一段新的颜色 `c`(前提是 `c` 未被处理过,即 `mask & (1 << c) == 0`)。 - 新状态为 `(mask | (1 << c), c)`,我们需要计算从当前位置开始,尽可能多地保留颜色 `c` 的石头。 - 具体来说,可以预处理 `count[l][r][c]` 表示区间 `[l, r]` 内颜色 `c` 的石头数量,然后枚举 `r` 来找到最优的连续段。
最新发布
04-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值