A. Restoring Three Numbers
#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
int main()
{
#ifdef LOCAL
//freopen("C:/input.txt", "r", stdin);
#endif
ll x, y, z, p;
cin >> x >> y >> z >> p;
if (p < x)
swap(x, p);
if (p < y)
swap(y, p);
if (p < z)
swap(z, p);
printf("%I64d %I64d %I64d\n", p - x, p - y, p - z);
return 0;
}
B. Make Them Equal
可以將某個數字加一次v或者減一次v不限制操作次數 找到一個最小的v可以將數字變爲相同
#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
int main()
{
#ifdef LOCAL
//freopen("C:/input.txt", "r", stdin);
#endif
vector<int> v;
int n;
cin >> n;
for (int i = 0; i < n; ++i)
{
int x;
cin >> x;
v.push_back(x);
}
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end());
if (v.size() > 3)
cout << -1 << endl, exit(0);
if (v.size() == 3 && v[1] - v[0] != v[2] - v[1])
cout << -1 << endl, exit(0);
if (v.size() == 3)
cout << v[1] - v[0] << endl;
else if (v.size() == 2)
{
int x = v[1] - v[0];
if (x % 2 == 0)
x /= 2;
cout << x << endl;
}
else
cout << 0 << endl;
return 0;
}
C. Gourmet Cat <枚舉>
三種食物 告訴你周幾喫哪種食物 問從周幾齣發能夠喫的最長時間
#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
int main()
{
#ifdef LOCAL
//freopen("C:/input.txt", "r", stdin);
#endif
ll x[3], z[3];
cin >> x[0] >> x[1] >> x[2]; //147 26 35
ll X = min({ x[0] / 3, x[1] / 2, x[2] / 2 }); //整週
x[0] -= X * 3, x[1] -= X * 2, x[2] -= X * 2; //餘下物品
ll ans = X * 7;
int y[] = { 0, 1, 2, 0, 2, 1, 0 };
for (int i = 0; i < 7; ++i) //開始
{
z[0] = x[0], z[1] = x[1], z[2] = x[2];
int cnt = 0;
for (int j = i; z[y[j]]--; j = (j + 1) % 7)
cnt++;
ans = max(ans, X * 7 + cnt);
}
cout << ans << endl;
return 0;
}
D. Walking Robot <模擬>
機器人有普通電池和太陽能充電電池 0爲無光1爲有光 可以選擇消耗一個電池走一步 陽光下可以消耗一個普通電池走一步獲得一個充電電池 問最遠能走多遠
#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
int main()
{
#ifdef LOCAL
//freopen("C:/input.txt", "r", stdin);
#endif
int n, a, b; //充電電池 電池
cin >> n >> b >> a;
int A = a, B = b;
for (int i = 1; i <= n; ++i)
{
int s;
scanf("%d", &s);
if (s && B && A < a)
A = min(a, A + 1), --B;
else if (A)
--A;
else
--B;
if (!A && !B)
cout << i << endl, exit(0);
}
cout << n << endl;
return 0;
}
E. Two Teams <數據結構> <模擬>
兩個教練選人 每次選數值最大的並且將旁邊的k個也選走 問每個人都被那個教練選走了
#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 2e5 + 10;
int l[N], r[N]; //左側右側編號
int a[N], b[N], c[N]; //b表示a數組從大到小編號
void sel(int x, int p) //選中x
{
r[l[x]] = r[x], l[r[x]] = l[x]; //拼接lr
c[x] = p; //記錄結果
}
int main()
{
#ifdef LOCAL
//freopen("C:/input.txt", "r", stdin);
#endif
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]), l[i] = i - 1, r[i] = i + 1, b[i] = i;
sort(b + 1, b + n + 1, [](int x, int y) { return a[x] > a[y]; });
int p = 1;
for (int i = 1; i <= n; ++i) //從大到小選取
{
if (c[b[i]]) //已經被選
continue;
int k = l[b[i]]; //兩側座標
for (int j = 0; k && j < m; ++j)
sel(k, p), k = l[k];
k = r[b[i]];
for (int j = 0; k && j < m; ++j)
sel(k, p), k = r[k];
sel(b[i], p);
p = p == 1 ? 2 : 1;
}
for (int i = 1; i <= n; ++i)
putchar('0' + c[i]);
cout << endl;
return 0;
}
寫醜了的map版
#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 2e5 + 10;
bool one[N]; //是否1隊
int main()
{
#ifdef LOCAL
freopen("C:/input.txt", "r", stdin);
#endif
map<int, int> pos, val; //位置順序 值順序
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; ++i)
{
int v;
scanf("%d", &v);
pos[i] = v;
val[v] = i;
}
int flag = 1;
while (!val.empty())
{
int p = val.rbegin()->second; //最大值位置
for (int i = 0; i < k; ++i) //左側
{
auto it = pos.lower_bound(p);
if (it == pos.begin())
break;
--it;
if (flag) one[it->first] = 1;
val.erase(it->second);
pos.erase(it);
}
for (int i = 0; i < k; ++i) //右側
{
auto it = pos.upper_bound(p);
if (it == pos.end())
break;
if (flag) one[it->first] = 1;
val.erase(it->second);
pos.erase(it);
}
if (flag) one[p] = 1;
val.erase(pos[p]);
pos.erase(p);
flag ^= 1;
}
for (int i = 1; i <= n; ++i)
putchar(one[i] ? '1' : '2');
cout << endl;
return 0;
}
F. Shovels Shop <dp> <貪心>
n個物品買k個 有m個優惠每買x個物品其中y個就免費 問最小費用
如果買k個不管有沒有優惠肯定買最便宜的k個,每個優惠策略可以重複使用所以如果同樣是買x個一個優惠y1一個優惠y2則取最大的。
購買使用優惠時肯定是將大小相近的作爲一組一起購買,因爲儘量優惠較大的。進行排序(其實找到前k小已經排序了)。
令f[i]表示購買前i個的最小代價,枚舉已經購買的物品數量嘗試使用每個優惠進行轉移取最小值。
#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 2e5 + 10;
int a[N], b[N], s[N];
int f[N]; //買前i個物品的最小代價
int main()
{
#ifdef LOCAL
//freopen("C:/input.txt", "r", stdin);
#endif
int n, m, k;
cin >> n >> m >> k;
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
sort(a + 1, a + n + 1); //貪心選擇儘量便宜的k個 並且dp過程中需要價值連續
for (int i = 1; i <= k; ++i)
s[i] = s[i - 1] + a[i]; //前綴和優化轉移
for (int i = 0; i < m; ++i)
{
int x, y; //買x免費y
scanf("%d%d", &x, &y);
b[x] = max(b[x], y); //儘量多
}
memset(f, 0x3f, sizeof(f));
f[0] = 0; //沒有物品代價0
for (int i = 1; i <= k; ++i) //物品
for (int j = 1; j <= i; ++j) //一次性購買量
f[i] = min(f[i], f[i - j] + s[i] - s[i - j + b[j]]); //只花費後半部分
cout << f[k] << endl;
return 0;
}
G. Minimum Possible LCM <枚舉>
任選兩個數字 求最小的最小公倍數
記錄每個數字出現次數和出現下標,暴力枚舉公因子i並乘上倍數j查詢數值是否出現,如果同一個公因子i有兩個倍數j出現則計算答案並且break,因爲後面會更大。
即使是極端情況複雜度也在1e8以內。
#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e7 + 10;
int cnt[N], pos[N]; //數值出現次數 數值編號
int main()
{
#ifdef LOCAL
//freopen("C:/input.txt", "r", stdin);
#endif
int n;
cin >> n;
ll ans = LINF, p, q;
for (int i = 1; i <= n; ++i)
{
int x;
scanf("%d", &x);
++cnt[x];
if (cnt[x] > 1 && ans > x) //出現2次可以直接作爲答案
ans = x, p = pos[x], q = i; //記錄上次的編號和i
pos[x] = i;
}
for (int i = 1; i < N; ++i) //公約數
{
int k = 0; //當前公約數最小的數字的倍率
for (int j = 1; i * j < N; ++j) //倍率
if (cnt[i * j])
{
if (k) //之前已有一個
{
if (ans > 1LL * i * j * k) //公約數*兩個數的倍
ans = 1LL * i * j * k, p = pos[i * k], q = pos[i * j]; //記錄編號
break; //後面只會更大
}
else
k = j; //記錄倍率
}
}
if (p > q)
swap(p, q);
cout << p << " " << q << endl;
return 0;
}