Codeforces 792C. Divide by Three 贪心+分类讨论

题意:给一个数字字符串,让你删除尽可能少的数位,使得这个数能够被3整除,并且不能有前导0存在。

思路:所有数位加起来%3得到的值mod,那么就有三种情况

mod==0:直接输出

mod==1:要么删除一个数位%3=1的数,要么删除两个数位%3=2的数

mod==2:要么删除一个数位%3=2的数,要么删除两个数位%3=1的数

其中前导零有个大坑,如果我们删数位的两种情况都可以,但是有一种情况会导致删除前导零,删除前导零的位数也要计算进去,细节很重要。为了尽可能的少产生前导零,当我们删除数位的时候,应该从后往前删除。(这个过程我用了栈来存储,分别算了两种情况的删除位数 然后作比较)

丑陋的AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e9+7;
char num[100100];
int deal_1[100100];
bool vis_1[100100];
int deal_2[100100];
bool vis_2[100100];
stack<int> sta1,sta2;   //sta1存放%3值为1的数位置的下标 sta2同理
int len;
int del_cnt1,del_cnt2;
bool flag;
void print(int n)
{
    if(n==1)
    {
        if(del_cnt1==len)
        {
            if(flag)
            {
                printf("0
");
            }
            else
                printf("-1
");
            return;
        }
        for(int i=0; i<len; i++)
            if(vis_1[i])
                printf(("%c"),num[i]);
    }
    else
    {
        if(del_cnt2==len)
        {
            if(flag)
            {
                printf("0
");
            }
            else
                printf("-1
");
            return;
        }
        for(int i=0; i<len; i++)
            if(vis_2[i])
                printf(("%c"),num[i]);
    }
    printf("
");
}

void del(int n)     //计算前导0
{
    int cnt=0;
    if(n==1)
    {
        for(int i=0; i<len; i++)
            if(vis_1[i])
            {
                if(num[i]!='0')
                    return;
                else if(del_cnt1)
                {
                    vis_1[i]=false;
                    ++del_cnt1;
                }
            }
    }
    else if(n==2)
    {
        for(int i=0; i<len; i++)
            if(vis_2[i])
            {
                if(num[i]!='0')
                    return;
                else if(del_cnt2)
                {
                    vis_2[i]=false;
                    ++del_cnt2;
                }
            }
    }
}
int main()
{
    memset(vis_1,true,sizeof(vis_1));
    memset(vis_2,true,sizeof(vis_2));
    del_cnt1 = del_cnt2 = maxn;
    flag = false;
    len = strlen(num);
    int mod =0;
    for(int i=0; i<len; i++)
    {
        if(!flag && num[i]=='0')
            flag=true;
        deal_2[i] = deal_1[i] = (num[i]-'0')%3;
        mod += deal_1[i];
        if(deal_1[i]==1)
            sta1.push(i);
        else if(deal_2[i]==2)
            sta2.push(i);
    }
    mod%=3;
    if(mod == 0)
    {
        printf("%s
",num);
        return 0;
    }
    else if(mod == 1)
    {
        if(!sta1.empty())
        {
            del_cnt1=0;
            vis_1[sta1.top()] = false;
            ++del_cnt1;
            del(1);
        }
        if(sta2.size()>=2)
        {
            del_cnt2=0;
            vis_2[sta2.top()] = false;
            sta2.pop();
            vis_2[sta2.top()] = false;
            sta2.pop();
            del_cnt2+=2;
            del(2);
        }
    }
    else
    {
        if(!sta2.empty())
        {
            del_cnt1=0;
            vis_1[sta2.top()] = false;
            ++del_cnt1;
            del(1);
        }
        if(sta1.size()>=2)
        {
            del_cnt2=0;
            vis_2[sta1.top()] = false;
            sta1.pop();
            vis_2[sta1.top()] = false;
            sta1.pop();
            del_cnt2+=2;
            del(2);
        }
    }

    if(del_cnt1>del_cnt2)
        print(2);
    else
        print(1);
    return 0;
}
原文地址:https://www.cnblogs.com/MyCodeLife-/p/7736391.html