A. Elephant(Codeforces 617A)
思路
因爲是求最小行走次數,因此可以貪心地儘可能多走
代碼
#include <bits/stdc++.h>
using namespace std;
int x;
int main() {
scanf("%d", &x);
printf("%d\n", x / 5 + (x % 5 > 0));
return 0;
}
B. Chocolate(Codeforces 617B)
思路
想象一下,在每兩個
需要注意的是序列的前綴
代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 105;
int n, head;
ll cnt, ans, sum, a[maxn];
int main() {
cin >> n;
for(int i = 0; i < n; i++) {
cin >> a[i];
sum += a[i];
}
if(sum == 0) {
puts("0");
return 0;
}
// 找到序列中的第一個1
for(head = 0; head < n; head++) {
if(a[head] == 1) {
break;
}
}
ans = 1;
// 統計連續的0的個數同時累乘
for(int i = head; i < n; i++) {
if(a[i] == 1) {
ans *= (cnt + 1);
cnt = 0;
}
else {
cnt++;
}
}
cout << ans << endl;
return 0;
}
C. Watering Flowers(Codeforces 617C)
思路
顯然圓心和與圓心不重合的點,這兩點能且僅能刻畫一個圓。設有
這樣,通過離散化思想我們就可以將問題轉化爲:在
我們可以用
考慮是否能讓其中一個圓的集合有序,從而省略判斷。於是我們將點集
到此問題圓滿解決了。但實際上還有複雜度更低的算法。我們可以將
代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
// 點結構體
struct Point {
ll x, y;
Point() {}
Point(ll x, ll y): x(x), y(y) {}
void input() {
scanf("%I64d%I64d", &x, &y);
}
ll sqrDis(const Point& o) const {
return (x - o.x) * (x - o.x) + (y - o.y) * (y - o.y);
}
};
const int maxn = 2010;
int n;
Point f1, f2, a[maxn];
ll ans, Max[maxn];
// 排序用的比較函數
bool cmp(Point a, Point b) {
return f1.sqrDis(a) < f1.sqrDis(b);
}
int main() {
scanf("%d", &n);
f1.input();
f2.input();
for(int i = 1; i <= n; i++) {
a[i].input();
}
sort(a + 1, a + n + 1, cmp);
Max[n+1] = 0;
// 預處理出同O2距離最遠的點
for(int i = n; i >= 1; i--) {
Max[i] = max(f2.sqrDis(a[i]), Max[i+1]);
}
ans = Max[1];
for(int i = 1; i <= n; i++) {
ans = min(ans, f1.sqrDis(a[i]) + Max[i+1]);
}
printf("%I64d\n", ans);
return 0;
}
D. Polyline(Codeforces 617D)
思路
用筆在草稿紙上嘗試後可以合理地提出假設,答案只有
- 若三點有某個座標分量兩兩相等,則可以用一個線段覆蓋三個點。
- 若三點中有且僅有兩個點
p1,p2 有某個座標分量相等(不妨表示爲x1=x2 )。且另一個分量滿足yp3 不在yp1 和yp2 之間,則可以用兩個線段覆蓋三個點。 - 但以上兩個條件都不滿足的話,就只能用三個線段來覆蓋三個點。
代碼
#include <bits/stdc++.h>
using namespace std;
int x[5], y[5];
int solve() {
// 第一種情況
if(x[1] == x[2] && x[2] == x[3]) {
return 1;
}
if(y[1] == y[2] && y[2] == y[3]) {
return 1;
}
int a, b, c;
// 枚舉上述p1,p2點,判斷第二種情況
for(int i = 1; i <= 3; i++) {
for(int j = 1; j <= 3; j++) {
for(int k = 1; k <= 3; k++) {
if(i == j || j == k || i == k) {
continue;
}
if(x[i] == x[j]) {
a = min(y[i], y[j]);
b = max(y[i], y[j]);
c = y[k];
if(c <= a || c >= b) {
return 2;
}
}
if(y[i] == y[j]) {
a = min(x[i], x[j]);
b = max(x[i], x[j]);
c = x[k];
if(c <= a || c >= b) {
return 2;
}
}
}
}
}
// 否則是第三種情況
return 3;
}
int main() {
for(int i = 1; i <= 3; i++) {
cin >> x[i] >> y[i];
}
cout << solve() << endl;
return 0;
}
E. XOR and Favorite Number(Codeforces 617E)
思路
如果對區間和比較敏感的話,求區間的異或和可以先對原數組做預處理,然後就能做到常數時間查詢。因而我們令
即使做了優化,還是很難用合適的時間複雜度做查詢。於是我們考慮通過小區間的答案推大區間的答案(或者相反)。假設我們已經知道
建立了
另外要注意幾個易錯點:
sum 數組的大小至少要開成數組中的數的2倍(因爲取異或值後可能比原數大)。insert 和erase 函數中兩條語句的順序不能變(因爲統計的時候都是不計idx 這個位置的元素的)。- 所有的查詢區間在輸入後
l 要自減1 (當然也可以在後面的操作中減)。 insert(0) 這條語句不可刪去(例如k=1,a[1]=1 且第一個查詢是[1,1] 時,如果不加這句的話查詢結果就是0 )。
代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10, maxa = 1e6 + 10;
int n, m, k, size;
// 排序用的查詢結構體
struct query {
int l, r, idx;
query() {}
query(int l, int r, int idx): l(l), r(r), idx(idx) {}
int block() const {
return l / size;
}
bool operator < (const query& o) const {
return block() == o.block() ? r < o.r : block() < o.block();
}
};
// 莫隊算法
struct M {
ll cnt;
int a[maxn], sum[maxa<<1];
ll ans[maxn];
query q[maxn];
// 輸入數據
void input(int n) {
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
for(int i = 2; i <= n; i++) {
a[i] ^= a[i-1];
}
}
// 向當前區間中加入新元素
void insert(int idx) {
cnt += sum[a[idx]^k];
sum[a[idx]]++;
}
// 想當前區間中擦除邊界元素
void erase(int idx) {
sum[a[idx]]--;
cnt -= sum[a[idx]^k];
}
void solve(int m) {
int l, r;
for(int i = 1; i <= m; i++) {
scanf("%d%d", &l, &r);
q[i] = query(--l, r, i);
}
// 排序
sort(q + 1, q + m + 1);
insert(0);
// 暴力移動指針
int L = 0, R = 0;
for(int i = 1; i <= m; i++) {
l = q[i].l;
r = q[i].r;
for(; R < r; insert(++R));
for(; L > l; insert(--L));
for(; R > r; erase(R--));
for(; L < l; erase(L++));
ans[q[i].idx] = cnt;
}
}
// 輸出答案
void output(int m) {
for(int i = 1; i <= m; i++) {
printf("%I64d\n", ans[i]);
}
}
}o;
int main() {
scanf("%d%d%d", &n, &m, &k);
size = sqrt(m);
o.input(n);
o.solve(m);
o.output(m);
return 0;
}