Codeforces 792C Divide by Three By Assassin [模拟]

A positive integer number n is written on a blackboard. It consists of not more than 105 digits. You have to transform it into a beautiful number by erasing some of the digits, and you want to erase as few digits as possible.

The number is called beautiful if it consists of at least one digit, doesn't have leading zeroes and is a multiple of 3. For example, 0, 99, 10110 are beautiful numbers, and 00, 03, 122 are not.

Write a program which for the given n will find a beautiful number such that n can be transformed into this number by erasing as few digits as possible. You can erase an arbitraty set of digits. For example, they don't have to go one after another in the number n.

If it's impossible to obtain a beautiful number, print -1. If there are multiple answers, print any of them.

Input
The first line of input contains n — a positive integer number without leading zeroes (1 ≤ n < 10100000).

Output
Print one number — any beautiful number obtained by erasing as few as possible digits. If there is no answer, print  - 1.

Examples
input
1033
output
33
input
10
output
0
input
11
output
-1
Note
In the first example it is enough to erase only the first digit to obtain a multiple of 3. But if we erase the first digit, then we obtain a number with a leading zero. So the minimum number of digits to be erased is two.

题目猛一看真的很坑啊,真的以为是dp,但是怎么想也想不通,所以换了一种思路直接成了纯模拟了。

思路:给定一个串,要求该数去掉尽可能少的位,使得剩下的数可以被3整除(不就是所有位的和可以被3整除?)。那么我们怎么去?Look!

因为是模3,其实总共也就3种大情况!

1.sum%3==0 直接输出即可
2.sum%3==1
(1)去掉1个数a 且有a%3==1
(2)去掉2个数a、b 且有a%3==2&&b%3==2
3.sum%3==2
(1)去掉1个数a 且有a%3==2
(2)去掉2个数a、b 且有a%3==1&&b%3==1

这里要从后向前去,因为如果数位足够多的情况下无需去前导零,剩下的位数更长

然后硬模拟就行了,但是过程中需要注意的问题还是非常多的!比如说
1.前导零从什么地方开始去除
2.保证至少有1位数,不会全部去掉了,比如11、1
3.如果需要输出0的时候不要当作前导零直接去掉了

具体很多的细节我都写在代码的注释中了,但是我的思路感觉还是比较复杂的,应该还有更加简洁的思路!下面分享我的丑代码

#include<bits/stdc++.h>
using namespace std;
int v1[100005],v2[100005];
const int inf=0xffff;
int main(){
    string s;
    int y0,y1,y2,zero;                  //y0,y1,y2分别表示%3==012的位数,zero表示是否存在0int times1,times2;                  //用来后面择更优解的两个计数器,计数是去掉的数量 
    long long sum;                      //计算串的总数 
    while(cin>>s){
        times1=times2=inf;              //计数器置到最大值,因为我们要的是去掉的越少越好 
        memset(v1,0,sizeof(v1));        //v1,v2这里用来标记哪些位被去掉 
        memset(v2,0,sizeof(v2));
        zero=y0=y1=y2=sum=0;        
        for(int i=0;i<s.size();i++){
            if(s[i]=='0') zero=1;
            sum+=(s[i]-'0');
            if((s[i]-'0')%3==0) y0++;   //统计各类位的个数 
            else if((s[i]-'0')%3==1) y1++;
            else if((s[i]-'0')%3==2) y2++;
        }
        if(sum%3==0) {                  //如果整除直接输出 
            cout<<s<<endl;
            continue;
        }
        else if(sum%3==1){                          //如果%3==1 
            if(y1>0){                               //去掉 1%3==1
                for(int i=s.size()-1;i>=0;i--){         
                    if((s[i]-'0')%3==1){
                        v1[i]=1;
                        times1=1;
                        break;
                    }
                }
            }
            if(y2>=2){                              //或者去掉(2+2)%3==1
                int sub=2;
                for(int i=s.size()-1;i>=0;i--){
                    if((s[i]-'0')%3==2){
                        sub--;
                        v2[i]=1;
                    }
                    if(sub==0){
                        times2=2;
                        break;
                    } 
                }
            }
        }
        else if(sum%3==2){                          //如果%3==2 
            if(y2>0){
                for(int i=s.size()-1;i>=0;i--){     //去掉 2%3==1
                    if((s[i]-'0')%3==2){
                        v1[i]=1;
                        times1=1;
                        break;
                    }
                }
            }
            if(y1>=2){                              //去掉(1+1)%3==2
                int sub=2;
                for(int i=s.size()-1;i>=0;i--){
                    if((s[i]-'0')%3==1){
                        sub--;
                        v2[i]=1;
                    }
                    if(sub==0){
                        times2=2;
                        break;
                    } 
                }
            }
        } 
        int k1=0,k2=0;                              //注意,这是一个坑点,如果之前一些数都被去掉了,那么我们要从去掉的前几位之后去前导零 
        for(;v1[k1]==1;k1++);
        for(;v2[k2]==1;k2++);
        for(int i=k1;i<s.size()-1;i++){             //去掉方案1if(s[i]=='0') times1++,v1[i]=1;
            else if(v1[i]==1) continue;
            else break;
        }
        for(int i=k2;i<s.size()-1;i++){             //去掉方案2if(s[i]=='0') times2++,v2[i]=1;
            else if(v2[i]==1) continue;
            else break;
        }
        if(times1<=times2&&times1<s.size()){        //坑点2,一定要有 times1<s.size(),因为可能都去掉了!如11 
            for(int i=0;i<s.size();i++){
                if(v1[i]==0){
                    cout<<s[i];
                }
            }
        }
        else if(times1>times2&&times2<s.size()){
            for(int i=0;i<s.size();i++){
                if(v2[i]==0){
                    cout<<s[i];
                }
            }
        }
        else if(zero==1){                           //如果上式全都不成立,但是有0存在,那么就直接输出0 
            cout<<0;
        }
        else cout<<-1;                              //否则真的没可能了,输出-1 
        cout<<endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值