AtCoder BC155E

Problem Link

\(len\le 1000000\)

像这种数据范围基本就是 \(O(n)\) 扫了

我们倒着扫,记 \(s_{i}\) 为当前位的数字,\(s_{i-1}\) 为前一位

如果 \(s_i\) 为 10(在后面的操作中会出现的),那么就执行进位 \(s_i=0,s_{i-1} =s_{i-1}+1\)

如果 \(s_i<5\),那么很明显用 \(s_i\) 张是最优的

如果 \(s_i>5\),那么就用一张大的去换 \(10-s_i\) 张小的,因为 \(s_i>5\),即使是最坏的情况 \(s_{i-1}<5\):进一位会让前一位多消耗一张,但 $10-s_i+1+1\le s_i $ 明显成立,所以一定不会更劣,反而有可能更优

如果 \(s_i=5\),就要分类讨论了

如果 \(s_{i-1}\ge5\),那么此时进一位会让前一位使用一张,明显更,于是就用一张大的去换 \(10-5=5\) 张小的

如果 \(s_{i-1}<5\),那么此时进一位会让前一位使用一张,明显更,于是直接用 5 张就行了

注意要判断 \(s_0\) 最后是否有被进位

// This code wrote by chtholly_micromaker(MicroMaker)
#include <bits/stdc++.h>
#define reg register
using namespace std;
const int MaxN=1000050;
template <class t> inline void read(t &s)
{
    s=0;
    reg int f=1;
    reg char c=getchar();
    while(!isdigit(c))
    {
        if(c=='-')
            f=-1;
        c=getchar();
    }
    while(isdigit(c))
        s=(s<<3)+(s<<1)+(c^48),c=getchar();
    s*=f;
    return;
}
char s[MaxN];
signed main(void)
{
    scanf("%s",s+1);
    reg int n=strlen(s+1);
    s[0]=0;
    reg int ans=0;
    for(int i=1;i<=n;++i)
        s[i]-='0';
    for(int i=n;i>=1;--i)
    {
        if(s[i]==10)
        {
            s[i]=0;
            ++s[i-1];
        }
        if(s[i]==5)
        {
            if(s[i-1]>=5)
            {
                ++s[i-1];
                ans+=5;
            }
            else
            {
                ans+=5;
            }
        }
        else if(s[i]<5)
        {
            ans+=s[i];
        }
        else if(s[i]>5)
        {
            ans+=10-s[i];
            ++s[i-1];
        }
    }
    ans+=s[0];
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/chinesepikaync/p/12319303.html