【2021京东秋招】01比
问题
小明有一个只包含0和1的字符串,现在小明希望将整个字符串尽可能的切割成多个字符串,要求是每个字符串里面0出现的次数和1出现的次数的比例是一致的。
解释:假设一个字符串出现0的次数是a次,出现1的次数是b另一个字符串出现0的次数是c次,出现1的次数是d次,那么这两个字符串01出现次数比例相同表示a:b=c:d,即 a*d=b*c。注意这里a,b,c,d都是可以为0的。现在对于一个字符串的所有前缀字符串,输出最多可以切割成多少个符合要求的字符串。
输入描述:
第一行一个整数n,表示01字符串的长度,1<=n<=500000第二行一个长度为n的01字符串。
输出描述:
一行n个整数,第i个数表示原字符串中下标由0到i组成的前缀字符串可以切割出多少符合要求的字符串。
示例
输入: 9
010100001
输出: 1 1 1 2 1 2 1 1 3
解答
#include <iostream>
#include <map>
using namespace std;
int _gcd(int a, int b) {
if (b == 0) return a;
return _gcd(b, a % b);
}
int main() {
int n; cin >> n;
string s; cin >> s;
map<pair<int, int>, int> mp;
int n0 = 0, n1 = 0;
for (int i = 0; i < s.size(); i++) {
if (s[i] == '0') n0++;
else n1++;
if (!n0 || !n1) cout << i + 1 << ' ';
else {
int gcd = _gcd(n0, n1);
int ans = ++mp[{n0 / gcd, n1 / gcd}];
cout << ans << ' ';
}
}
cout << endl;
}
重点思路
题目需要求数值呈一定比例的关系。若a:b=c:d,则a、b和c、d除以对应的最小公倍数后可以被约为相同的两个数。
使用动态规划,两数除以其最小公倍数后的两个数作为状态量,这个状态量保存可被切割的次数。遍历整个字符串,每次都将该状态量对应的结果加1。例如010101
,可分为3组,当前已经得知0101
为2,所以在此基础上+1输出3即可。