【CodeForces】【贪心】988E-Divisibility by 25

CodeForces 988E Divisibility by 25

题目

◇题目传送门◆

题目大意

给定一个小于 10 18 的正整数,现可将这个数的相邻两位进行交换,问最少经过多少次交换后,它能被25整除。若无论如何交换仍不能则输出-1。注意不能出现前导0。

思路

我们可以使用小学的知识说明:当一个数的末尾两位是00,25,50,75时,这个数就能被25整除。

这里以25为例:

  1. 我们从后往前找出所有可能的2和5,分别放入两个不同的数组中。

  2. 枚举所有的2和5的搭配方案,计算出将2和5分别移至末尾的所需步数,并加上前导0的个数,取其中的最小值,即答案。

实现细节

我们可以使用字符串来替代整数,从而避免整数转字符串的问题。

我们可使用常量数组来表示应取的数。

正解代码

#include<cstdio>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
const int F[3][2]={{2,5},{5,0},{7,5}};
string s;
int len;
vector<int> t[3];

int Abs(int x) {return x<0?-x:x;}

int GetWrongNum(int pos1,int pos2) {
    if(len==2)return 0;
    int ret=0;
    for(int i=0;i<len;i++) {
        if(i==pos1||i==pos2)
            continue;
        if(s[i]=='0')ret++;
        else return ret;
    }
    return INF;
}

int Solve() {
    int ret=INF;
    int pos1=-1,pos2=-1;

    for(int i=len-1;i>=0&&pos2==-1;i--) {
        if(s[i]=='0')
            pos1==-1?(pos1=i):(pos2=i);
    }
    if(pos1!=-1&&pos2!=-1)
        ret=len-pos1-1+len-pos2-2;

    for(int i=0;i<3;i++) {
        t[0].clear(),t[1].clear();
        for(int j=0;j<2;j++)
            for(int k=len-1;k>=0;k--)
                if(s[k]-'0'==F[i][j])
                    t[j].push_back(k);

        for(int j=0;j<t[0].size();j++)
            for(int k=0;k<t[1].size();k++) {
                int tmp=len-1-t[1][k];
                tmp+=len-2-t[0][j]+(t[0][j]>t[1][k]?1:0);
                tmp+=GetWrongNum(t[0][j],t[1][k]);
                ret=min(ret,tmp);
            }
    }

    return ret>=INF?-1:ret;
}

int main() {
    #ifdef LOACL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    cin>>s;
    len=s.size();
    printf("%d\n",Solve());
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37656398/article/details/81198603
25