A. Lucky Year(Codeforces 808A)
思路
本題的入手點是,想明白一個正整數只有一個非零位是什麼概念。
一個正整數只有一個非零位,那麼這個數就只有最高位有非零位,也就可以表示成表示成這樣:
那麼我們可以設計出這樣的算法:將正整數
代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
string s;
ll k, d;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> s;
k = s[0] - '0' + 1;
for(int i = 1; i <= s.size() - 1; i++) {
k *= 10;
}
stringstream ss;
ss << s;
ss >> d;
cout << k - d << endl;
return 0;
}
B. Average Sleep Time(Codeforces 808B)
思路
本題的入手點在於,熟悉前綴和數組或能夠構造出所需數列。
這道題要求的東西實際上是一個“奇怪的平均值”:“奇怪的和
當然,除了前綴和外,還可以直接計算答案。直接計算答案的思路是考慮數組中每個元素在
現在根據規律嘗試推廣,於是嘗試求推廣後數列的通項公式設
(以下代碼爲方法
代碼
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int n, k, a;
double ans;
int main() {
ios::sync_with_stdio(false);
cout.tie(0);
cin.tie(0);
cin >> n >> k;
for(int i = 1; i <= n; i++) {
cin >> a;
ans += 1.0 * a * min(min(k, n - k + 1), min(i, n - i + 1));
}
cout << setprecision(7) << fixed;
cout << ans / (n - k + 1) << endl;
return 0;
}
C. Tea Party(Codeforces 808C)
思路
本題的入手點在於逐步地滿足條件。
首先,我們一定可以給每個杯子倒上一半的水,如果不行的話就無解。那麼接下來只剩下把水壺中的水全部倒出來這一個條件需要滿足了。顯然,可以通過貪心地從大杯子到小杯子依次將杯子倒滿來滿足條件。
代碼
#include <bits/stdc++.h>
using namespace std;
typedef pair <int, int> p;
const int maxn = 110;
int n, w, a, idx, cur, tmp, ans[maxn];
p ps[maxn];
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> w;
for(int i = 1; i <= n; i++) {
cin >> a;
ps[i] = p(a, i);
}
sort(ps + 1, ps + n + 1);
for(int i = 1; i <= n; i++) {
a = ps[i].first;
idx = ps[i].second;
cur = max(cur, a / 2 + (a % 2 > 0));
ans[idx] = cur;
w -= cur;
if(w < 0) {
cout << -1 << endl;
return 0;
}
if(i == n && w > 0) {
ans[idx] += w;
}
}
for(int i = n; i >= 1; i--) {
a = ps[i].first;
idx = ps[i].second;
ans[idx] += tmp;
if(ans[idx] > a) {
tmp = ans[idx] - a;
ans[idx] = a;
}
else {
tmp = 0;
}
}
for(int i = 1; i <= n; i++) {
cout << ans[i] << ' ';
}
return 0;
}
D. Array Division(Codeforces 808D)
思路
本題的入手點在於考察將一個元素移動後會對結果有什麼影響。
假設有下面的數組:
我們將其做一個劃分(用豎線):
顯然,將
可以觀察到,將
那麼顯然,如果已經知道了豎線的位置,同時分別知道了豎線左邊的數字之和
所以我們可以預處理出前綴和數組與後綴和數組,枚舉豎線的位置的同時用
代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
int n, a[maxn];
ll d, L[maxn], R[maxn];
set <ll> ls, rs;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> a[i];
}
for(int i = 1; i <= n; i++) {
L[i] = L[i - 1] + a[i];
}
for(int i = n; i >= 1; i--) {
R[i] = R[i + 1] + a[i];
}
for(int i = 1; i <= n; i++) {
d = R[i + 1] - L[i];
if(d == 0 || d < 0 && d % 2 == 0 && ls.count(-d / 2)) {
cout << "YES" << endl;
return 0;
}
ls.insert(a[i]);
}
for(int i = n; i >= 1; i--) {
d = L[i - 1] - R[i];
if(d == 0 || d < 0 && d % 2 == 0 && rs.count(-d / 2)) {
cout << "YES" << endl;
return 0;
}
rs.insert(a[i]);
}
cout << "NO" << endl;
return 0;
}
E. Selling Souvenirs(Codeforces 808E)
思路
本題的入手點是,在動態規劃中選用貪心策略。
雖然本題長得很像揹包問題,但是因爲物品數量和揹包容量的乘積太大,所以不能用傳統的方法來做。跟傳統的問題相比,物品的種類只有三種(重量分別爲
因此我們可以將三種物品的價值分別放入數組
那麼可不可以在動態規劃的過程中考慮三種物品而不是兩種物品呢?答案是可以,但是要考慮的情況就要複雜一些,比如,當要向背包加入重量爲
代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxm = 3e5 + 5;
vector <ll> tab[4];
int n, m, w, x, c[3][maxm];
ll ans, d[maxm], sum[maxm];
bool cmp(ll a, ll b) {
return a > b;
}
int main() {
ios::sync_with_stdio(false);
cout.tie(0);
cin.tie(0);
cin >> n >> m;
for(int i = 1; i <= n; i++) {
cin >> w >> x;
tab[w].push_back(x);
}
for(int i = 1; i <= 3; i++) {
sort(tab[i].begin(), tab[i].end(), cmp);
}
for(int j = 0; j < m; j++) {
sum[j + 1] = sum[j];
if(j < tab[3].size()) {
sum[j + 1] += tab[3][j];
}
}
if(tab[1].size() > 0) {
d[1] = tab[1][0];
c[1][1] = 1;
}
for(int i = 2; i <= m; i++) {
for(int j = 1; j <= 2; j++) {
if(c[j][i - j] >= tab[j].size()) {
continue;
}
if(d[i] < d[i - j] + tab[j][c[j][i - j]]) {
d[i] = d[i - j] + tab[j][c[j][i - j]];
c[j][i] = c[j][i - j] + 1;
c[j^3][i] = c[j^3][i - j];
}
}
}
for(int i = 0; i <= m; i++) {
ans = max(ans, d[i] + sum[(m - i) / 3]);
}
cout << ans << endl;
return 0;
}
(其它題目略)