版权声明:欢迎转载,不要求署名~~~ https://blog.csdn.net/shadandeajian/article/details/81986363
传送门: 题目
题意:
给一个数字,你可以删除字符串某一个位置的字符,使其满足下列条件:
- 数字没有前导0
- 数字能够被3整除
求操作次数的最小值。
题解:
我们知道,一个数字所有位上的数字相加,能够被3整除,那么这个数字就能被3整除,所以我们可以依靠这个条件判断条件2。如果除的时候有余数,那么只需要从原来数字中删除一位,这一位的mod恰好是余数,那么就可以满足条件。我们也可以删除两位,这两位每位的mod都是3-余数,相当于一种曲线救国的方法。因为是求3的倍数,所以只有这两种情况,可以用数学证明,因为本人数学比较菜,就不证明了,其实只要仔细想一想,就会觉得这么做是有道理的。
AC代码:
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
using namespace std;
int judge(string str) {//判断是否能被3整除
int sum = 0;
for (auto x : str)
sum = (sum + x - '0') % 3;
return sum | !str.size();
}
void removelead0(string& str) {//去掉前导0
while ((*str.begin()) == '0' && str.size() > 1)
str.erase(str.begin());
}
int main(void) {
string str, str1, str2;
cin >> str;
int reminder = judge(str), reminder2 = 3 - reminder, t1 = 1, t2 = 2;
str1 = str2 = str;
for (int i = (int)str.size() - 1; i >= 0; i--) {
if ((str[i] - '0') % 3 == reminder && t1)//去掉多余的那个数,然后就可以被32整除了
str1.erase(i, 1), --t1;
if ((str[i] - '0') % 3 == reminder2 && t2)//曲线救国
str2.erase(i, 1), --t2;
}
t1 = judge(str1), t2 = judge(str2), removelead0(str1), removelead0(str2);
if (t1 && t2)
return 0 * puts("-1");
if ((str1.size() > str2.size() && (!t1)) || t2)
str2 = str1;
cout << str2 << endl;
return 0;
}