题解-数字删除

题目描述

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

给定一个正整数,去掉其中若干个数字后剩下的数字按原左右次序将组成一个新的正整数。请问最少删去几个数字,能够使得这个新的正整数合法(不含前导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;
}
相关推荐
可爱系程序猿5 小时前
键鼠都正常、只有手柄映射才提示 dinput8.dll?DirectInput 接口和游戏目录怎么对齐
程序人生·游戏·电脑
weixin_424183616 小时前
开放—封闭原则实战(下):基于策略的流程编排与编译期多态
c++·分布式·系统架构
wuminyu7 小时前
C++协程实现接收端的零拷贝Buffer管理原理剖析
java·linux·c语言·jvm·c++
m0_380743877 小时前
C++中的freopen的用法实例详解
开发语言·c++
jimy18 小时前
polymorph.cpp里面的“析构函数、智能指针”问题
开发语言·c++
朝朝辞暮i8 小时前
C++ 第 6 课:switch —— 多状态选择
开发语言·c++·算法
朝朝辞暮i9 小时前
C++ 第 4 课:if / else —— 让程序自己做决定
开发语言·c++
苏打豆9 小时前
Pinocchio源码阅读——刚体运动物理量空间变换及求导
c++·线性代数·算法·矩阵·机器人
m0_380743879 小时前
Qt中导航栏实现的详细指南
开发语言·c++
估值探索者9 小时前
【Python量化策略实战 #02】多因子合成mom和vol两因子打分合成
开发语言·c++·python·数据挖掘·c#