牛客小白月赛86
牛客小白月赛86
A 水盐平衡
解题思路:
通分,然后比较分子大小。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
ll gcd(int a, int b)
{
return b ? gcd(b, a % b) : a;
}
ll lcm(int a, int b)
{
return a * b / gcd(a, b);
}
void solve()
{
int a, b, c, d;
cin >> a >> b >> c >> d;
ll t = lcm(b, d);
ll k1 = t / b;
ll k2 = t / d;
a *= k1;
c *= k2;
if (a < c)
{
puts("Y");
}
else
{
puts("S");
}
}
int main()
{
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
B 水平考试
解题思路:
模拟判断即可。
没有得5分的情况。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
void solve()
{
string a, b;
cin >> a >> b;
if (b.size() == 1)
{
if (a.size() > 1)
{
puts("0");
return;
}
else
{
if (a != b)
{
puts("0");
return;
}
else
{
puts("10");
return;
}
}
}
else
{
vector<int> cnt(200);
for (auto c : b)
{
cnt[c]++;
}
for (auto c : a)
{
if (cnt[c] == 0)
{
puts("0");
return;
}
cnt[c]++;
}
puts("10");
}
}
int main()
{
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
C 数组段数
解题思路:
预处理前缀和。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
void solve()
{
int n, m;
cin >> n >> m;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
vector<int> pre(n + 1);
for (int i = 1; i <= n; i++)
{
if (a[i] == a[i - 1])
{
pre[i] = pre[i - 1];
}
else
{
pre[i] = pre[i - 1] + 1;
}
}
while (m--)
{
int l, r;
cin >> l >> r;
int ans = pre[r] - pre[l - 1];
if (a[l - 1] == a[l])
{
ans++;
}
cout << ans << endl;
}
}
int main()
{
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
return 0;
}
D 剪纸游戏
解题思路:
搜索连通块,判断该连通块是否是矩形。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};
void solve()
{
int n, m;
cin >> n >> m;
vector<string> g(n + 1);
for (int i = 1; i <= n; i++)
{
cin >> g[i];
g[i] = ' ' + g[i];
}
vector<vector<bool>> vis(n + 1, vector<bool>(m + 1, false));
auto check = [&](int a, int b)
{
if (a < 1 || a > n || b < 1 || b > m)
{
return false;
}
if (vis[a][b])
{
return false;
}
if (g[a][b] == '*')
{
return false;
}
return true;
};
ll ans = 0;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
if (g[i][j] == '.' && !vis[i][j])
{
vector<pii> v(4, {i, j});
int cnt = 0;
auto bfs = [&](int x, int y)
{
queue<pii> q;
q.push({x, y});
vis[x][y] = true;
while (q.size())
{
auto u = q.front();
q.pop();
int a = u.fi;
int b = u.se;
cnt++;
for (int i = 0; i < 4; i++)
{
int nx = a + dx[i];
int ny = b + dy[i];
if (check(nx, ny))
{
vis[nx][ny] = true;
if (nx <= v[0].fi && ny <= v[0].se)
{
v[0] = {nx, ny};
}
if (nx <= v[1].fi && ny >= v[1].se)
{
v[1] = {nx, ny};
}
if (nx >= v[2].fi && ny >= v[2].se)
{
v[2] = {nx, ny};
}
if (nx >= v[3].fi && ny <= v[3].se)
{
v[3] = {nx, ny};
}
q.push({nx, ny});
}
}
}
};
bfs(i, j);
if (v[0].se == v[3].se && v[0].fi == v[1].fi && v[1].se == v[2].se && v[2].fi == v[3].fi)
{
if ((v[1].se - v[0].se + 1) * (v[2].fi - v[1].fi + 1) == cnt)
{
ans++;
}
}
// for (auto t : v)
// {
// cout << t.fi << ' ' << t.se << endl;
// }
// cout << i << ' ' << j << ' ' << ans << ' ' << cnt << endl;
}
}
}
cout << ans << endl;
}
int main()
{
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
return 0;
}
E 可口蛋糕
解题思路:
对于每一个起点,答案是固定的。
我们先得到对于每个起点基本满足饱和度的边界,然后看从边界到最后所有满足饱和度的时候可口值的前缀和最大值。
由于本题数据范围为\(10^6\),只能用\(O(n)\)找最大。
\(ps:尝试用st表查区间最大值卡的死死的。\)
所以这里我们可以根据饱和值边界,记录连续段的起点。
然后从右往左用单调栈记录当前区间最大值,顺便根据饱和右边界,枚举左起点。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
void solve()
{
int n, W;
cin >> n >> W;
vector<ll> w(n + 10), d(n + 10), prew(n + 10), pred(n + 10);
for (int i = 1; i <= n; i++)
{
cin >> w[i];
prew[i] = prew[i - 1] + w[i];
}
for (int i = 1; i <= n; i++)
{
cin >> d[i];
pred[i] = pred[i - 1] + d[i];
}
vector<int> r(n + 1, -1);
int idx = 1;
ll ans = -1e18;
vector<vector<int>> v(n + 10);
for (int i = 1; i <= n; i++)
{
while (idx <= n && prew[idx] - prew[i - 1] < W)
{
idx++;
}
if (idx <= n)
{
r[i] = idx;
v[idx].push_back(i);
ans = max(ans, pred[r[i]] - pred[i - 1]);
}
}
ll cur = 0;
vector<ll> q;
for (int i = n; i > 0; i--)
{
while (q.size() && pred[i] > q.back())
{
q.pop_back();
}
q.push_back(pred[i]);
for (auto j : v[i])
{
ans = max(ans, q.front() - pred[j - 1]);
}
}
cout << ans << endl;
}
int main()
{
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
return 0;
}
F 喜欢序列
解题思路:
首先,不难发现,如果一段序列可以连在一起,全部连在一个整体的贡献一定大于将他分开的贡献。
我们构建差分序列。
对于差分序列中连续的\(1\)看作一个整体线段。
我们要做的就是在修改过程中不断合并线段(或者说区间)。
由于本题中的连接性质差分数组中可以完美体现,所以我们接下来只看差分数组即可。
差分数组上进行区间修改在这不多赘述\((b[l] + w,b[r + 1] - w)\)。
在修改过程中,如果原本不为\(1\)的位置变为了\(1\)我们就要进行合并,并更新合并带来的总体贡献。
在修改过程中,如果原本为\(1\)的位置变为了其他数字我们就要进行分裂,并更新合并带来的总体贡献。
举例:
合并:\((....)(x...)\to(....x...)\)
分类:\((....x...) \to (....)(x...)\)
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
void solve()
{
int n, m;
cin >> n >> m;
vector<ll> a(n + 1), b(n + 1);
for (int i = 1; i <= n; i++)
{
cin >> a[i];
b[i] = a[i] - a[i - 1];
}
ll ans = 0;
set<pii> s;
int l = 1;
auto add = [&](int l, int r)
{
ll len = r - l + 1;
s.insert({l, r});
ans += len * len;
};
auto del = [&](int l, int r)
{
ll len = r - l + 1;
s.erase({l, r});
ans -= len * len;
};
for (int i = 2; i <= n; i++)
{
if (b[i] != 1)
{
add(l, i - 1);
l = i;
}
}
add(l, n);
auto deal = [&](int idx, ll w)
{
if (idx == 1 || idx > n)
{
return;
}
ll t = b[idx];
b[idx] += w;
if (b[idx] == 1)
{
//(....)(x...)
//(....x...)
auto it = s.lower_bound({idx, -1});
auto cur = *it;
auto p = *prev(it);
del(p.fi, p.se);
del(cur.fi, cur.se);
add(p.fi, cur.se);
}
else if (t == 1)
{
//(....x...)
//(....)(x...)
auto it = s.lower_bound({idx, -1});
auto cur = *prev(it);
del(cur.fi, cur.se);
add(cur.fi, idx - 1);
add(idx, cur.se);
}
};
while (m--)
{
int l, r, w;
cin >> l >> r >> w;
if (w != 0)
{
deal(l, w);
deal(r + 1, -w);
}
cout << ans << endl;
}
}
int main()
{
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
return 0;
}