CodeForces 988E Divisibility by 25
题目
题目大意
给定一个小于 的正整数,现可将这个数的相邻两位进行交换,问最少经过多少次交换后,它能被25整除。若无论如何交换仍不能则输出-1。注意不能出现前导0。
思路
我们可以使用小学的知识说明:当一个数的末尾两位是00,25,50,75时,这个数就能被25整除。
这里以25为例:
我们从后往前找出所有可能的2和5,分别放入两个不同的数组中。
枚举所有的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;
}