这题挺邪的,主要是观察分析性质吧
首先对于一段区间,它肯定满足以下条件之一:
1.左端点有 2
2.右端点有2
3.左右端点都有1
那么就有,当前区间的答案的奇偶性相同的比当前答案小的答案都在这一段区间里
这样找一段最长的和为奇数的区间就可以构造出所有合法的奇数的答案
找出一段最长的和为偶数的区间就可以构造出所有合法偶数的方案
复杂度 O(n)
代码:
#include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cctype> #include <cstdio> #include <locale> using namespace std; const int MAXN = 1000005; int n, m, l1, r1, l2, r2, fir, lst; bool has1; int a[MAXN], sum[MAXN]; pair<int,int> ans[MAXN << 1]; inline int getval() { register int c = getchar(); while (!isupper(c)) c = getchar(); return (c == 'T' ? 2 : 1); } inline int rd() { register int x = 0, c = getchar(); while (!isdigit(c)) c = getchar(); while (isdigit(c)) { x = x * 10 + (c ^ 48); c = getchar(); } return x; } int main() { n = rd(); m = rd(); for (int i = 1; i <= n; ++i) { a[i] = getval(); sum[i] = sum[i - 1] + a[i]; has1 |= (a[i] == 1); } for (int i = 1; i <= n; ++i) if (a[i] == 1) { fir = i; break; } for (int i = n; i >= 1; --i) if (a[i] == 1) { lst = i; break; } if (!has1) { register int x = 0; while (m--) { x = rd(); if (x & 1) puts("NIE"); else printf("1 %d ", (x >> 1)); } return 0; } if (sum[n] & 1) { l1 = 1; r1 = n; while (l1 <= r1) { ans[sum[r1] - sum[l1 - 1]] = make_pair(l1, r1); if (a[l1] == 2) ++l1; else if (a[r1] == 2) --r1; else { ++l1; --r1; } } if ((fir - 1) < (n - lst)) { l2 = fir + 1; r2 = n; } else { l2 = 1; r2 = lst - 1; } while (l2 <= r2) { ans[sum[r2] - sum[l2 - 1]] = make_pair(l2, r2); if (a[l2] == 2) ++l2; else if (a[r2] == 2) --r2; else { ++l2; --r2; } } } else { l2 = 1; r2 = n; while (l2 <= r2) { ans[sum[r2] - sum[l2 - 1]] = make_pair(l2, r2); if (a[l2] == 2) ++l2; else if (a[r2] == 2) --r2; else { ++l2; --r2; } } if ((fir - 1) < (n - lst)) { l1 = fir + 1; r1 = n; } else { l1 = 1; r1 = lst - 1; } while (l1 <= r1) { ans[sum[r1] - sum[l1 - 1]] = make_pair(l1, r1); if (a[l1] == 2) ++l1; else if (a[r1] == 2) --r1; else { ++l1; --r1; } } } register int x = 0; while (m--) { x = rd(); if (!ans[x].first) puts("NIE"); else printf("%d %d ", ans[x].first, ans[x].second); } return 0; }