给定序列\(a\),\(a_i\)能够传任意数给\(a_{i + 1}\),要求序列最终严格递增。问是否能够。ios
能够贪心作,保证严格递增以后将多余的数所有传下去。c++
仔细研究得出结论,最优为\(\{0, 1, \cdots,n - 1\}\),所以只要保证任意位置的前缀和大于最优序列便可。数组
#includeusing namespace std; #define DEBUG 0 #define int long long #define all(x) x.begin(), x.end() #define sz(x) (int(x.size())) #define vt std::vector #define pb push_back using ll = long long; using db = double; using pii = pair ; using pll = pair ; const int maxn = 1e3 + 50; const int inf = 0x3f3f3f3f3f; template inline void wpr(Args... args) { std::cout << '\n'; } template void wpr(T val, Args... args) { std::cout << val << " "; wpr(args...); } void solve(){ int n, tot = 0, ok = 1; std::cin >> n; for (int i = 0; i < n; ++ i){ int rd; std::cin >> rd; tot += rd; if (tot < (i * (i + 1) / 2)) ok = 0; } std::cout << (ok ? "yes" : "no") << "\n"; } signed main(){ ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int t = 1; std::cin >> t; while (t--) solve(); return 0; }
There are \(n\) houses, you should find some points so that the summary distance from all the houses to the exhibition is minimal. For each case output the number of different positions for the exhibition. Note : the distance is Manhattan Distance .函数
此题考查的是绝对值不等式。spa
当序列长度为奇数时,显然中位数为肯定的,那么答案只有一个。code
当序列长度为偶数时,则最小值在\(x\)在范围\(a_{\frac{n}{2}} \sim a_{\frac{n}{2}-1}\)内皆知足。ci
所以当\(n\)为偶数时,答案为\(x,y\)轴可选区间长度的乘积。element
void solve(){ int n; std::cin >> n; vtfx(n), fy(n); for (int i = 0; i < n; ++ i) std::cin >> fx[i] >> fy[i]; sort(all(fx)), sort(all(fy)); if (n & 1) std::cout << 1 << "\n"; else std::cout << 1ll * (fx[n / 2] - fx[n / 2 - 1] + 1) * (fy[n / 2] - fy[n / 2 - 1] + 1) << "\n"; }
Find the position of the maximum element in the array in no more than \(20\) queries. For each query you can ask the position of the second maximum element in a subsegment \(a[l..r]\).get
不难分析出是一个二分题,实际上交互通常都是二分。it
因为咱们只能询问第二大的值,咱们首先询问全局第二大的值并将其设为端点,而后再二分寻找另外一端点。保证该端点刚好可使得区间内的第二大值为全局第二大值(也就是该端点为最大值)。
首先讨论最大值在左仍是在右,由于须要讨论端点状况。
inline int query(int l, int r){ std::cout << "? " << l << " " << r << endl; int res; std::cin >> res; return res; } void solve(){ int n; std::cin >> n; int l = 1, r = n; int p = query(l, r); if (p != 1 and p == query(1, p)){ l = 1, r = p; while (l + 1 < r){ int m = l + r >> 1; if (p == query(m, p)) l = m; else r = m; } std::cout << "! " << l << "\n"; }else { l = p, r = n; while (l + 1 < r){ int m = l + r >> 1; if (p == query(p, m)) r = m; else l = m; } std::cout << "! " << r << "\n"; } }
Give you an array \(a\) of length \(n\). Find a subarray \(a[l\cdots r]\) with length at least \(k\) with the largest median. Note: $n\le 2\cdot10^5 $
比赛的时候猜了个结论为直接使用长度为\(k\)的滑动窗口,用multiset
维护,遗憾的是猜错了。
实际上有过一闪而过的想法,利用二分法解决问题,可是苦于没法找到\(\mathcal{O(n)}\)内能够完成任务的check
函数。
本题中的中位数能够理解为:在一段序列中有超过一半的数大于等于该中位数。本题的官方题解给的是利用前缀和快速求解。
分为三步:
median
,替换原序列,当元素大于median
时为1
不然为-1
。sum
和最小前缀和数组mpre
。由于,序列中位数大于等于median
等价于该序列和前缀和的值大于0.k
,所以能够利用sum[i] - mpre[i - k] >= 1
判断以i
为结尾,长度至少为k
序列的最大前缀和是否大于 0
。最为精彩的就是将中位数转化为前缀和并进行替换。
int n, k; vtf; inline bool check(int p){ vt a(n + 1), sum(n + 1), mpre(n + 1); for (int i = 1; i <= n; ++ i) a[i] = (f[i - 1] >= p ? 1 : -1); for (int i = 1; i <= n; ++ i){ sum[i] = sum[i - 1] + a[i]; mpre[i] = min(mpre[i - 1], sum[i]); } int ok = 0; for (int i = k; i <= n; ++ i) if (sum[i] - mpre[i - k] >= 1) ok = 1; return ok; } void solve(){ std::cin >> n >> k; f.resize(n); for (int i = 0; i < n; ++ i) std::cin >> f[i]; int l = 1, r = 2e5 + 50; while (l + 1 < r){ int m = l + r >> 1; if (check(m)) l = m; else r = m; } std::cout << l << "\n"; }