联合训练
1.Educational Codeforces Round 183
A:取模
B:贪心
思路有点问题,感谢队友教学
对于问题,关注整体而不是过程,即对于操作,重要的不是操作,而是采用操作发生了什么,带来什么影响,以及多个状态叠加影响(确定优先级)对局面的转变
关注那些起始状态,中间状态,最终状态,甚至是极端状态
点击查看代码
//关注0,1,2操作发现0/1会造成确定-
//对于2(不确定)来说:讨论2与x(n - (0/1)的大小关系)
//x > 2:变为?即可
//x <= 2:转变为-
while(_ -- ) {
cin >> n >> k;
cin >> s;
int a, b, c;
a = count(s.begin(), s.end(), '0'),
b = count(s.begin(), s.end(), '1'),
c = count(s.begin(), s.end(), '2');
string ans(n, '+');
for(int i = 0; i < n; ++ i) {
if(i < a + c || i > n - 1 - b - c) ans[i] = '?';
if(k == n || i < a || i > n - 1 - b) ans[i] = '-';//n=k时一定可删全部
}
cout << ans << "\n";
}
C:贪心
通过转化将ab串转化为1/-1(对偶)串,总和为0时则ab相等
计算当前数组的总和 𝑠,要使总和等于 0 ,必须删除总和为 𝑠的一个数段
(问题就简化为找出总和为 𝑠的最短线段)
采用前缀和,遍历线段的右边界,求每个和为𝑠的最短线段 (l <= r, prefr+1 - prefl = s),即prefr+1 - s = prefl
注意取值范围-n~n,存储空间为2*n数组(采用x+n记录),或者使用map结构
点击查看代码
int cur = count(s.begin(), s.end(), 'a') -
count(s.begin(), s.end(), 'b');//总和
map<int, int> mp;//前缀和及位置
int pr = 0;
mp[pr] = -1;
ans = n;
for(int i = 0; i < n; ++ i) {
pr += s[i] == 'a' ? 1 : -1;
mp[pr] = i;//更新pr位置求全局
if(mp.count(pr - cur)) {//求[l,i]存在cur
ans = min(ans, i - mp[pr - cur]);
}
}
cout << (ans == n ? -1 : ans) << "\n";