A. Maximum Increase(Codeforces 702A)
思路
最暴力的思路是用兩個指針枚舉子串的首尾位置。但是這樣的複雜度是
代碼
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int n, ans, head, tail, a[maxn];
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
ans = 1;
head = 1;
tail = 2;
while(tail <= n) {
// 如果尾指針能往下走就往下走
if(a[tail] > a[tail-1]) {
ans = max(ans, tail++ - head + 1);
}
// 否則重置首指針和尾指針
else {
head = tail++;
}
}
printf("%d\n", ans);
return 0;
}
B. Powers of Two(Codeforces 702B)
思路
根據複雜度的提示覺得這題應該是先枚舉一個
代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5, maxNum = 1e9;
int n, cnt, d, ub, lb, Pow[100], a[maxn];
ll ans;
int main() {
Pow[0] = 1;
for(cnt = 1; ; cnt++) {
Pow[cnt] = Pow[cnt-1] << 1;
if(Pow[cnt] >= maxNum) {
break;
}
}
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
sort(a + 1, a + n + 1);
for(int i = 1; i <= n; i++) {
for(int j = 0; j <= cnt; j++) {
// d爲a[i]固定後應該找的a[k]
d = Pow[j] - a[i];
if(d <= 0) {
continue;
}
// 查找a[k]的下界
lb = lower_bound(a + i + 1, a + n + 1, d) - a;
// 查找a[k]的上界
ub = upper_bound(a + i + 1, a + n + 1, d) - a;
if(ub - lb > 0) {
ans += ub - lb;
}
}
}
printf("%I64d\n", ans);
return 0;
}
C. Cellular Network(Codeforces 702C)
思路
根據數據量猜想是二分查找半徑(如果直接枚舉,判斷的話複雜度太高)。在二分查找中最多可以以
問題轉化成是否能在規定的複雜度內判斷
(另外在我朋友的提醒下知道這題有線性的算法,簡單說是用兩個指針分別指向城市和塔,然後移動指針並用離某個城市最近的塔距該城市的距離更新最小半徑。這樣跑出來是
代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair <ll, ll> p;
const int maxn = 1e5 + 5, maxm = 1e5 + 5, maxNum = 1e9;
int n, m, l, r, mid, idx, city[maxn], tower[maxm];
p itv[maxm];
ll Max, a[maxm], b[maxm];
// 基於ST表的RMQ部分
struct ST {
ll st[maxn][32];
int log2[maxn];
void initLog(int n) {
log2[1] = 0;
for(int i = 2; i <= n; i++) {
log2[i] = log2[i-1];
if((1 << log2[i] + 1) == i) {
++log2[i];
}
}
}
void init(int n, ll* a) {
for(int i = n - 1; i >= 0; i--) {
st[i][0] = a[i];
for(int j = 1; (i + (1 << j) - 1) < n; j++) {
st[i][j] = max(st[i][j-1], st[i+(1<<j-1)][j-1]);
}
}
}
ll rmq(int l, int r) {
int len = r - l + 1, k = log2[len];
return max(st[l][k], st[r-(1<<k)+1][k]);
}
}o;
// 判斷給定半徑是否滿足條件
bool ok(ll R) {
// 處理出m個區間區間
for(int i = 1; i <= m; i++) {
itv[i] = p(tower[i] - R, tower[i] + R);
}
// 對區間以區間左端點爲關鍵字排序
sort(itv + 1, itv + m + 1);
for(int i = 1; i <= m; i++) {
a[i-1] = itv[i].first;
b[i-1] = itv[i].second;
}
// 初始化ST表
o.init(m, b);
// 對每個city[i]判斷是否沒有區間包含它
for(int i = 1; i <= n; i++) {
idx = lower_bound(a, a + m, (ll)city[i]) - a;
if(a[idx] == city[i]) {
continue;
}
if(idx == 0) {
return false;
}
Max = o.rmq(0, idx - 1);
if(Max < city[i]) {
return false;
}
}
return true;
}
int main() {
o.initLog(maxm);
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) {
scanf("%d", &city[i]);
}
for(int i = 1; i <= m; i++) {
scanf("%d", &tower[i]);
}
// 二分查找滿足條件的最小半徑
l = -1;
r = 2 * maxNum;
while(r - l > 1) {
mid = (l + r) >> 1;
ok(mid) ? r = mid : l = mid;
}
printf("%d\n", r);
return 0;
}
D. Road to Post Office(Codeforces 702D)
思路
這種運動學的題目,無非是用模擬法或公式法解決。首先想到模擬法,應該先對問題分類,當
代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll D, K, A, B, T, t, ans;
int main() {
cin >> D >> K >> A >> B >> T;
ans += A * min(D, K);
D = max(D - K, 0LL);
// 計算一個週期內的最小運動時間
t = min(A * K + T, B * K);
// 將整數倍區間的路程走完
ans += D / K * t;
D %= K;
// 將剩餘的路程走完
ans += min(A * D + T, B * D);
cout << ans << endl;
return 0;
}
(其它題目略)