题解-数字删除

题目描述

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

给定一个正整数,去掉其中若干个数字后剩下的数字按原左右次序将组成一个新的正整数。请问最少删去几个数字,能够使得这个新的正整数合法(不含前导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作为最终正整数的起始位置,

如果当前si不为'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;
}
相关推荐
lilili也2 小时前
C++:文件操作
c++
Lhan.zzZ2 小时前
C++多线程——std::thread与condition_variable形象理解
c++
头歌实践平台2 小时前
C++面向对象 - 运算符重载的应用
开发语言·c++·算法
思麟呀2 小时前
C++11并发编程:互斥锁
linux·开发语言·c++·windows
AC赳赳老秦2 小时前
OpenClaw批量任务队列优化:解决任务堆积、执行缓慢、优先级混乱问题
java·大数据·数据库·c++·自动化·php·openclaw
晚风予卿云月2 小时前
《二分答案》算法练习
数据结构·c++·算法·二分·竞赛·算法随笔
郭涤生2 小时前
C++ 各类数据的内存分区与读写性能详解
开发语言·c++
j_xxx404_2 小时前
Linux 线程日志系统设计:从策略模式、RAII 到 pthread 线程安全与内核写入路径|附源码
linux·运维·服务器·开发语言·c++·人工智能·策略模式
飞天狗1112 小时前
2025第十六届蓝桥杯c/c++B组国赛题解
c语言·c++·算法·蓝桥杯
努力努力再努力wz3 小时前
【Qt入门系列】:QLabel控件详解:从文本显示到图片展示,再到内容布局与伙伴机制
android·开发语言·数据结构·数据库·c++·qt·mysql