1 条题解
-
0
发现题解区都是奇偶性什么什么的,于是提供一种新的,我认为更简单,更好理解的解法。
首先数字总是 或 这一点肯定特别有用。
我们先钦定答案的左端点是 ,右端点可以在前缀和上二分到第一个 的位置 。
如果刚好满足和为 那就不用管。否则:
令 的和为 ,那么肯定有 且 。
证明:
若 ,那么必然可以通过减少 使得答案更小。
所以 。
若此时 ,那么必然可以通过令 使得更加满足答案。
证毕。
然后,正常情况下,我们肯定需要通过双指针检查最小满足的 。
但是不难发现,
-
一旦在右边 ,左边 (即 )时,就相当于给 减一了。
-
如果刚刚好满足给左边 右边不动(即 ),也相当于给 减一。
那么左右端点必须有 。那么反过来,我只需要知道 向右有多少个连续的 就行了,即每次有 的时候肯定要 。
更详细的,令 表示 往右有多少个连续的 。
如果 ,那么肯定满足上述的第一种情况。
如果 ,那么就是上述的第二种情况。
然后代码就会清新很多。
for(int i = n;i >= 1;i--){ if(a[i] == 'W') f[i] = 0, s[i] = 1; else f[i] = f[i+1] + 1, s[i] = 2; } for(int i = 1;i <= n;i++) s[i] += s[i-1]; while(q--){ int x; cin>>x; int l = 1, r = n, ans = -1; while(l <= r){ int mid = (l + r) >> 1; if(s[mid] >= x) r = mid - 1, ans = mid; else l = mid + 1; } if(ans == -1){ cout<<"NIE\n"; continue; } if(s[ans] == x){ cout<<"1 "<<ans<<'\n'; continue; } if(f[1] >= f[ans]){ if(ans + f[ans] > n) cout<<"NIE\n"; else cout<<1 + f[ans]<<" "<<ans + f[ans]<<'\n'; continue; } if(ans + f[1] > n) cout<<"NIE\n"; else cout<<2 + f[1]<<" "<<ans + f[1]<<'\n'; } -
- 1
信息
- ID
- 3882
- 时间
- 600ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者