牛客练习赛59
A.小乔和小灰灰
签到。
Code
/*
* Author: heyuhhh
* Created Time: 2020/3/13 19:00:59
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
template <template<typename...> class T, typename t, typename... A>
void err(const T <t> &arg, const A&... args) {
for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
#define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1000 + 5;
const string s = "XiaoQiao", t = "XiaoHuiHui";
string ss;
void run() {
cin >> ss;
int len = ss.length();
int t1 = 0, t2 = 0;
for(int i = 0; i < len; i++) {
if(t1 < 8 && ss[i] == s[t1]) ++t1;
if(t2 < 10 && ss[i] == t[t2]) ++t2;
}
if(t1 == 8 && t2 == 10) {
cout << "Happy" << '\n';
} else cout << "emm" << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
run();
return 0;
}
B.牛能和小镇
排序后贪心计算即可。
Code
/*
* Author: heyuhhh
* Created Time: 2020/3/13 19:12:53
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
template <template<typename...> class T, typename t, typename... A>
void err(const T <t> &arg, const A&... args) {
for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
#define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
int n;
ll a[N];
void run() {
cin >> n;
for(int i = 1; i <= n; i++) {
int x, y; cin >> x >> y;
a[i] = 1ll * y * (x - y) * (x - y);
}
sort(a + 1, a + n + 1);
ll ans = 0;
for(int i = 2; i <= n; i++) {
ans += a[i] - a[i - 1];
}
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
run();
return 0;
}
C.装备合成
题意:
牛牛有\({x}\)件材料\(a\)和\({y}\)件材料\(b\),用\(2\)件材料\(a\)和\(3\)件材料\(b\)可以合成一件装备,用\(4\)件材料\(a\)和\(1\)件材料\(b\)也可以合成一件装备。牛牛想要最大化合成的装备的数量,于是牛牛找来了你帮忙。
思路:
显然最终答案具有单调性。
那么二分答案\(t\),假设最后用第一种方法合成了\(A\)件装备,那么第二种方法合成了\(B\)件装备,那么可以列出如下式子:
- \(2A+4B\leq x,3A+B\leq y,A+B=t\).
最后可以解出\(A\)的范围。二分时\(check\)一下是否合法即可。
Code
/*
* Author: heyuhhh
* Created Time: 2020/3/13 19:21:23
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
template <template<typename...> class T, typename t, typename... A>
void err(const T <t> &arg, const A&... args) {
for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
#define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
ll a, b;
bool chk(ll t) {
ll l = ceil(1.0 * (4 * t - a) / 2), r = floor(1.0 * (b - t) / 2);
return l <= r && l <= t && r >= 0;
}
void run() {
cin >> a >> b;
int l = 0, r = INF, mid;
while(l < r) {
mid = (l + r) >> 1;
if(chk(mid)) l = mid + 1;
else r = mid;
}
cout << l - 1 << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
int T; cin >> T;
while(T--) run();
return 0;
}
D.取石子游戏
\(sg\)函数有规律,直接算就行。
Code
/*
* Author: heyuhhh
* Created Time: 2020/3/13 20:15:51
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
template <template<typename...> class T, typename t, typename... A>
void err(const T <t> &arg, const A&... args) {
for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
#define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
ll f[N];
int t;
void init() {
ll Max = 4e18;
f[1] = 1, f[2] = 3;
for(int i = 3;; i++) {
f[i] = f[i - 1] * 2;
if(i % 2 == 0) ++f[i];
if(f[i] >= Max) {
t = i; break;
}
}
}
void run() {
ll n; cin >> n;
int p = lower_bound(f + 1, f + t + 1, n) - f;
if(p & 1) cout << "XiaoQiao" << '\n';
else cout << "XiaoHuiHui" << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
init();
int T; cin >> T;
while(T--) run();
return 0;
}
E.石子搬运
题意:
现有\(n\)堆石子,每堆有\(a_i\)个石头。现在可以将这\(n\)堆石子划分为\(m\)堆,每堆贡献为\(k_i^2\)。
然后会发生\(q\)个事件,每个事件为\(x\ v\),即将第\(x\)堆石子个数变为\(v\)。
对于每个事件,回答最小贡献。
\(1\leq n\leq m\leq 400,q\leq 400\)。
思路:
对于每个事件我们单独计算,总体思路就是贪心,按照差值来进行贪心。
每次选择当前贡献能减少的最大值进行操作即可。
可以用一个优先队列来维护。shi
时间复杂度为\(O(qnlogn)\)。
代码如下:
Code
/*
* Author: heyuhhh
* Created Time: 2020/3/13 23:06:41
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
template <template<typename...> class T, typename t, typename... A>
void err(const T <t> &arg, const A&... args) {
for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
#define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 400 + 5;
int n, m, q;
int a[N];
ll calc(int v, int k) {
int r = v % k;
int t = v / k;
return 1ll * r * (t + 1) * (t + 1) + 1ll * (k - r) * t * t;
}
ll solve(int v, int k) {
return calc(v, k) - calc(v, k + 1);
}
void run() {
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i];
cin >> q;
while(q--) {
int id, v; cin >> id >> v;
a[id] = v;
priority_queue <pair<ll, pii>> q;
for(int i = 1; i <= n; i++) {
q.push(pair<ll, pii>{solve(a[i], 1), MP(a[i], 1)});
}
int k = m - n;
while(k--) {
pair <ll, pii> now = q.top(); q.pop();
int val = now.se.fi, t = now.se.se + 1;
q.push(pair<ll, pii>{solve(val, t), MP(val, t)});
}
ll ans = 0;
while(!q.empty()) {
pair <ll, pii> now = q.top(); q.pop();
int val = now.se.fi, t = now.se.se;
ans += calc(val, t);
}
cout << ans << '\n';
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
run();
return 0;
}
F.小松鼠吃松果
题意:
有\(m\)个位置,有\(n\)个时刻在某些位置会生长一个价值为\(v_i\)的果子,每个果子只会存在一秒。
现在你可以任意选择一个点作为起点,每一秒只能向左或者向右移动一步。问最后能得到的最大价值是多少。
思路:
我们按照时间进行排序,如果我们要吃至少两个果子,那么要满足的条件为:
- \(t_j-t_i\geq |p_i-p_j|\)。
我们将绝对值打开,有:
- \(p_i\geq p_j,t_j+p_j\geq t_i+p_i\);
- \(p_i<p_j,t_j-p_j\geq t_i-p_i\)。
那么令\(X_i=p_i+t_i,Y_i=t_i-p_i\)。
那么我们按照\(X_i\)进行排序,问题可以转化为带权\(lis\),\(Y_i\)就是每个数的高度。我们要求最长不下降子序列的最大权值和。利用树状数组维护即可。
注意这里我们将问题转化为了二维问题。我们推出第二个式子的前提是按照时间排序,又可以发现只要满足第二个式子,第一个式子也自然满足了。如果没注意到这一点,就是一个三维问题,就像题解那样用树套树或者\(cdq\)分治这些来解决。
代码如下:
Code
/*
* Author: heyuhhh
* Created Time: 2020/3/14 10:23:00
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
template <template<typename...> class T, typename t, typename... A>
void err(const T <t> &arg, const A&... args) {
for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
#define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
int n, m;
int a[N], b[N];
struct node {
int id, h, v;
bool operator < (const node &A) const {
if(id != A.id) return id < A.id;
return h < A.h;
}
}info[N];
struct BIT {
ll c[N];
int lowbit(int x) {return x & (-x);}
void upd(int x, ll v) {
for(; x < N; x += lowbit(x)) c[x] = max(c[x], v);
}
ll query(int x) {
ll res = 0;
for(; x; x -= lowbit(x)) res = max(res, c[x]);
return res;
}
}bit;
void run() {
cin >> n >> m;
for(int i = 1; i <= m; i++) cin >> a[i];
for(int i = 1; i <= m; i++) cin >> b[i];
for(int i = 1; i <= n; i++) {
int t, p, c; cin >> t >> p >> c;
int x = a[p], y = b[p] + t;
info[i] = node{y - x, x + y, c};
}
sort(info + 1, info + n + 1);
vector <int> v;
for(int i = 1; i <= n; i++) v.push_back(info[i].h);
sort(all(v));
v.erase(unique(all(v)), v.end());
for(int i = 1; i <= n; i++) {
int h = lower_bound(all(v), info[i].h) - v.begin() + 1;
bit.upd(h, bit.query(h) + info[i].v);
}
ll ans = bit.query(n);
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
run();
return 0;
}
重要的是自信,一旦有了自信,人就会赢得一切。