题解-数字删除

题目描述

小明最近在研究一个数字删除游戏,正要考考佳佳。游戏规则如下:

给定一个正整数,去掉其中若干个数字后剩下的数字按原左右次序将组成一个新的正整数。请问最少删去几个数字,能够使得这个新的正整数合法(不含前导0)且是3的倍数。

小明写下的数字太大,佳佳一时处理不了。请你帮他写一个程序处理出结果吧!

输入

第一行一个整数n,表示小明写下了n正整数。

第2~n+1行每行一个正整数Ai。

输出

共n行,每行一个整数,表示最少删去的数字的个数。如果没有合法的方案,请输出"ERR"(不含引号)。

样例

输入样例

3

1234

1000

2

输出样例

1

3

ERR

提示

【样例解释】

第一组删除1个留下的整数为234或123.

第二组删除3个留下的整数为0。

对于30%的数据,n≤5,Ai≤10910^9109且不含有数字0。

对于60%的数据,n≤5,A¡≤1010000010^{100000}10100000且不含有数字0.

对于100%的数据,n≤5,Ai≤1010000010^{100000}10100000 。(数字的长度可能达到100001位)

分析

可以用动态规划来解决(线性dp)

由于要求不含前导零,所以从后往前转移。

f[i][j]代表 第i位到最后一位组成的数,对3取模等于j时最少需要删的数字的数量

a[i]指 第i位数字模3的结果

则对于第i位数字,有删除和不删除两种情况

若删除,则f[i][j] = f[i + 1][j] + 1

若不删除,则f[i][j] = f[i + 1][(j - a[i] + 3) % 3](注意j - a[i]可能为负数,故需要进行处理)

最终状态转移方程为

f[i][j] = min(f[i + 1][j] + 1,f[i + 1][(j - a[i] + 3) % 3])

对于最终结果,

首先,我们可以枚举i作为最终正整数的起始位置,

如果当前s[i]不为'0'时,则代表可以枚举,即将前 i - 1 个数字全部删去,且保留第i位数字,则局部最优解为

i - 1 + f[i + 1][(0 - a[i] + 3) % 3] (即把状态转移方程的j替换为0),最终结果取最小值即为答案

ps.因为第i位需要保留,所以不能是 i - 1 + f[i][0]

又因为最后一位数字不一定能被3整除,所以只能从1枚举到len - 1,

若最有一位数字能被3整除,那加一个特判 res = min(res,len - 1)即可

代码

c++ 复制代码
#include<bits/stdc++.h>

using namespace std;

const int N = 100000 + 10,INF = 0x3f3f3f3f;

int n;
char s[N];
int a[N];
int f[N][3];

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);

    cin >> n;
    while(n--){
        cin >> s + 1;

        int len = strlen(s + 1);

        for(int i = 1;i <= len;i++) a[i] = (s[i] - '0') % 3;

        //初始化
        memset(f,0x3f,sizeof f);
        f[len][a[len]] = 0;
        if(a[len]) f[len][0] = 1;

        for(int i = len - 1;i >= 1;i--)
            for(int j = 0;j <= 2;j++)
                f[i][j] = min(f[i + 1][j] + 1,f[i + 1][(j - a[i] + 3) % 3]);
        
        int res = INF;
        for(int i = 1;i < len;i++)
            if(s[i] != '0') res = min(res,i - 1 + f[i + 1][(0 - a[i] + 3) % 3]);
        if(a[len] == 0) res = min(res,len - 1); // 特判

        if(res == INF) cout << "ERR\n";
        else cout << res << '\n';
    }

    return 0;
}
相关推荐
王老师青少年编程1 小时前
csp信奥赛C++高频考点专项训练之字符串 --【子串查找】:[NOIP 2009 提高组] 潜伏者
c++·字符串·csp·高频考点·信奥赛·子串查找·潜伏者
初願致夕霞1 小时前
基于系统调用的Linux网络编程——UDP与TCP
linux·网络·c++·tcp/ip·udp
小小de风呀3 小时前
de风——【从零开始学C++】(五):内存管理
开发语言·c++
CHANG_THE_WORLD4 小时前
C语言中的 %*s 和 %.*s 和C++的字符串格式化输出
c语言·c++·c#
螺丝钉的扭矩一瞬间产生高能蛋白5 小时前
QT的C++接口基础用法
c++·qt·嵌入式软件·嵌入式linux·linux应用
智者知已应修善业5 小时前
【51单片机模拟生日蜡烛】2023-10-10
c++·经验分享·笔记·算法·51单片机
智者知已应修善业6 小时前
【51单片机如何让LED灯从一亮到八,再从八亮到一】2023-10-13
c++·经验分享·笔记·算法·51单片机
qeen876 小时前
【数据结构】二叉树相关经典函数C语言实现
c语言·数据结构·c++·笔记·学习·算法·二叉树
良木生香6 小时前
【C++初阶】STL——List从入门到应用完全指南(1)
开发语言·数据结构·c++·程序人生·算法·蓝桥杯·学习方法