【做题笔记】板刷 AtCoder
[ABC364D] K-th Nearest#
很好想的题目。
首先可以考虑到答案具有单调性,所以对于每一次询问用二分处理即可。
然后考虑如何判合法。我们需要找到所有
时间复杂度
点击查看代码
#include <bits/stdc++.h>
#define int long long
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
using namespace std;
const int N = 2e5 + 10;
int n, q, a[N], k, b;
bool check(int x) {
int L = n+1, R = 0;
int l = 1, r = n;
while(l <= r) {
int mid = l + r >> 1;
if(a[mid] - b <= x) {
R = mid;
l = mid + 1;
} else {
r = mid - 1;
}
}
l = 1, r = n;
while(l <= r) {
int mid = l + r >> 1;
if(a[mid] - b >= -x) {
L = mid;
r = mid - 1;
} else {
l = mid + 1;
}
}
return (R-L+1) >= k;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> q;
For(i,1,n) cin >> a[i];
sort(a + 1, a + n + 1);
while(q--) {
int l = 0, r = 2e8, ans = 0;
cin >> b >> k;
while(l <= r) {
int mid = l + r >> 1;
if(check(mid)) {
ans = mid;
r = mid - 1;
} else {
l = mid + 1;
}
}
cout << ans << '\n';
}
return 0;
}
[ARC172A] Chocolate#
第一个想法是将所有的矩形面积求和并与给定区域面积作比较,然后会被最后一个样例卡掉。手推一下发现这个只是一个必要条件。
考虑到将较大的矩形放在左上角(角落)是最优的。然后考虑缩小判断范围,假设当前要放置长度为
于是枚举
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 1e3 + 5;
int n, m, p, a[N];
int sum(int r) {
int sum0 = 0;
For(i,1,p) if(a[i] >= r) sum0 += ((1ll << a[i]) * (1ll << a[i]));
return sum0;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m >> p;
For(i,1,p) cin >> a[i];
For(r,0,25) {
int H = (n / (1ll << r)), W = (m / (1ll << r));
int k = H * W * (1ll << r) * (1ll << r);
if(sum(r) > k) {
cout << "No\n";
return 0;
}
}
cout << "Yes\n";
return 0;
}
[AGC032E] Modulo Pairing#
考虑到如果没有模数,则可按照贪心思路将
发现
发现这个分割点具有单调性于是直接二分即可。二分同时计算即可。
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
using namespace std;
const int N = 2e5 + 10;
int n, m, ans = INT_MAX, a[N];
bool check(int x) {
int res = 0;
For(i,1,x) {
if(a[i] + a[x - i + 1] >= m) return 1;
res = max(res, a[i] + a[x - i + 1]);
}
For(i,x+1,2*n) {
if(a[i] + a[(2*n) - i + x + 1] < m) return 0;
res = max(res, a[i] + a[(2*n) - i + x + 1] - m);
}
ans = min(ans, res);
return 1;
}
signed main() {
//freopen("duck.in", "r", stdin);
//freopen("duck.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m;
For(i,1,2*n) cin >> a[i];
sort(a + 1, a + 2 * n + 1);
int l = 0, r = n;
while(l <= r) {
int mid = l + r >> 1;
if(check(mid * 2)) {
r = mid - 1;
} else {
l = mid + 1;
}
}
cout << ans << '\n';
return 0;
}
</details>
# [[ABC203D] Pond](https://www.luogu.com.cn/problem/AT_abc203_d)
有一点整体二分的感觉。
考虑先二分出中位数的最小值 $x$。然后对于原矩阵统计出 01 矩阵:当 $a_{i,j}$ 大于 $x$ 时,记为 $1$;反之记为 $0$。然后枚举子矩阵的左上角的端点坐标,同时用前缀和统计出 $((x1,y1),(x2,y2))$ 中的 $1$ 的个数。即 $> x$ 的个数。若存在矩阵 $>x$ 的个数小于 $\left \lfloor \frac{k^2}{2} \right \rfloor + 1$。则将二分的范围上界变小,否则下界变大。
最后二分出来的即为最终答案。(考虑原矩阵中存在子矩阵中 $> x$ 的数的个数小于 $\left \lfloor \frac{k^2}{2} \right \rfloor + 1$,并且这个数存在于这个矩阵并且尽可能的小。所以这个数肯定是某子矩阵数集的中位数,并且满足最小 -> ~~这几点一开始没有想清楚~~)。
时间复杂度 $O(n^2 \log n)$。
<details>
<summary>点击查看代码</summary>
```cpp
#include<bits/stdc++.h>
#define ll long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 8e2 + 10;
int n, k, a[N][N], b[N][N], c[N][N], ans = -1;
int ask(int x1, int y1, int x2, int y2) {
return (b[x2][y2] - b[x1-1][y2] - b[x2][y1-1] + b[x1-1][y1-1]);
}
bool check(int x) {
For(i,1,n) {
For(j,1,n) {
b[i][j] = b[i-1][j] + b[i][j-1] - b[i-1][j-1] + (a[i][j] > x);
}
}
bool f = 0;
For(i,1,n-k+1) {
For(j,1,n-k+1) {
int sum = ask(i, j, i+k-1, j+k-1);
f |= (sum < (k*k)/2+1);
}
}
return f;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> k;
For(i,1,n) For(j,1,n) cin >> a[i][j];
int l = 0, r = 1e9;
while(l <= r) {
int mid = l + r >> 1;
if(check(mid)) {
ans = mid;
r = mid - 1;
} else {
l = mid + 1;
}
}
cout << ans << '\n';
return 0;
}
[ABC310E] NAND repeatedly#
很典的套路。
考虑暴力从
记
- 若
,则 位的所有 都可转移至当前 为的 状态,并且 状态贡献加一(算上 本身)。即 ; - 若
,则 位的所有 都可转移至当前 为的 状态, 位的所有 都可转移至当前 为的 状态,并且 状态贡献加一(算上 本身)。即 ;
最后把所有的
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 1e6 + 10;
int n, s[2][N], ans = 0;
char a[N];
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
cin >> (a + 1);
s[a[1]-'0'][1]++;
For(i,2,n) {
if(a[i] == '0') {
s[0][i]++;
s[1][i] = s[0][i-1] + s[1][i-1];
} else {
s[0][i] = s[1][i-1];
s[1][i] = s[0][i-1] + 1;
}
}
For(i,1,n) ans += s[1][i];
cout << ans << '\n';
return 0;
}
[ABC311E] Defect-free Squares#
考察对待问题的转化。
直接枚举
换一个角度,记
只要快速求解
考虑正方形的合法长度具有单调性,直接二分长度,再
总时间复杂度为
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 5e3 + 10;
int n, m, q, sum[N][N], ans;
int ask(int x1, int y1, int x2, int y2) {
return (sum[x2][y2] - sum[x1-1][y2] - sum[x2][y1-1] + sum[x1-1][y1-1]);
}
signed main() {
cin >> n >> m >> q;
For(i,1,q) {
int x, y; cin >> x >> y;
sum[x][y]++;
}
For(i,1,n) {
For(j,1,m) {
sum[i][j] += (sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1]);
}
}
For(i,1,n) {
For(j,1,m) {
int l = 1, r = min(i, j), num = 0;
while(l <= r) {
int mid = l + r >> 1;
if(ask(i - mid + 1, j - mid + 1, i, j) == 0) {
num = mid;
l = mid + 1;
} else {
r = mid - 1;
}
}
ans += num;
}
}
cout << ans << '\n';
return 0;
}
[ABC313E] Duplicate#
需要注意力的一道题,没有反应过来 qwq。
先判断无解,显然如果有相邻的数同时不为
考虑每一位的贡献:当前位的贡献只与再它之后的数有关,考虑倒序计算贡献,记录当前操作数为
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
#define mod 998244353
using namespace std;
const int N = 1e6 + 10;
char s[N];
int n, ans;
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> (s + 1);
For(i,2,n-1) {
if(s[i] != '1' && s[i+1] != '1') {
cout << "-1\n";
return 0;
}
}
FOR(i,n,2) {
cout << ans << '\n';
ans = (ans * (s[i]-'0') % mod + (s[i]-'0') % mod) % mod;
}
cout << ans << '\n';
return 0;
}
[ABC315E] Prerequisites#
思维题。
假设
由于跟
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 2e5 + 10;
struct Node {
int v, nx;
} e[N << 1];
int n, c[N], h[N], tot, in[N], ans[N], len;
void add(int u, int v) {
e[++tot] = (Node){v, h[u]};
h[u] = tot;
}
void topu_sort() {
priority_queue<int> q;
For(i,1,n) if(!in[i]) q.push(i);
bool f = 0;
while(!q.empty()) {
int x = q.top();
q.pop();
if(f == 1) ans[++len] = x;
if(x == 1) f = 1;
for (int i = h[x]; i; i = e[i].nx) {
int y = e[i].v;
if(!(--in[y])) {
q.push(y);
}
}
}
FOR(i,len,1) cout << ans[i] << ' ';
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
For(i,1,n) {
cin >> c[i];
For(j,1,c[i]) {
int x; cin >> x;
add(i, x);
in[x]++;
}
}
topu_sort();
return 0;
}
[ABC317E] Avoid Eye Contact#
很无聊的题。
所有人的视线是固定的,于是可以预处理出那些位置不能走。然后 bfs 一下最短路径即可。
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 2e3 + 10;
const int dx[] = {0, 0, -1, 1};
const int dy[] = {-1, 1, 0, 0};
int n, m, sx, sy, ex, ey, ans[N][N];
struct Node {
int x, y;
};
char a[N][N];
bool vis[N][N], st[N][N];
bool stp(int x, int y) {
return (a[x][y] == '#' || a[x][y] == '>' || a[x][y] == '<' || a[x][y] == 'v' || a[x][y] == '^');
}
void bfs() {
queue<Node> q;
q.push((Node){sx, sy});
st[sx][sy] = 1;
while(!q.empty()) {
Node a = q.front();
q.pop();
For(i,0,3) {
int nx = a.x + dx[i], ny = a.y + dy[i];
if(nx >= 1 && nx <= n && ny >= 1 && ny <= m && !vis[nx][ny] && !st[nx][ny]) {
st[nx][ny] = 1;
ans[nx][ny] = ans[a.x][a.y] + 1;
q.push((Node){nx, ny});
}
}
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m;
For(i,1,n) For(j,1,m) cin >> a[i][j];
For(i,1,n) {
For(j,1,m) {
if(vis[i][j]) continue;
if(a[i][j] == 'S') sx = i, sy = j;
if(a[i][j] == 'G') ex = i, ey = j;
if(a[i][j] == '>') {
vis[i][j] = 1;
for (int k = j; k <= m; ++k) {
vis[i][k] = 1;
if(stp(i, k+1)) break;
}
} else if(a[i][j] == '<') {
vis[i][j] = 1;
for (int k = j; k >= 1; --k) {
vis[i][k] = 1;
if(stp(i, k-1)) break;
}
} else if(a[i][j] == 'v') {
vis[i][j] = 1;
for (int k = i; k <= n; ++k) {
vis[k][j] = 1;
if(stp(k+1, j)) break;
}
} else if(a[i][j] == '^') {
vis[i][j] = 1;
for (int k = i; k >= 1; --k) {
vis[k][j] = 1;
if(stp(k-1, j)) break;
}
} else if(a[i][j] == '#') vis[i][j] = 1;
}
}
bfs();
cout << (!ans[ex][ey] ? -1 : ans[ex][ey]) << '\n';
return 0;
}
[ABC318E] Sandwiches#
思维题。
记
答案的贡献即为
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 3e5 + 10;
int n, a[N], cnt[N], b[N], del[N], last[N], num[N], ans;
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
For(i,1,n) cin >> a[i];
For(i,1,n) {
cnt[a[i]]++;
if(!last[a[i]]) last[a[i]] = i;
b[i] = (i - last[a[i]] + 1) - cnt[a[i]];
num[a[i]] += b[i];
}
For(i,1,n) {
num[a[i]] -= (b[i] - del[a[i]]) * cnt[a[i]];
ans += (num[a[i]]);
del[a[i]] = b[i];
cnt[a[i]]--;
}
cout << ans << '\n';
return 0;
}
[ABC320E] Somen Nagashi#
很无聊的题目。
可以发现归队操作不用时刻维护。对于每一次操作
一眼线段树维护最小时刻,然后线段树上二分即可。
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define ls p<<1
#define rs p<<1|1
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 2e5 + 10;
struct Node {
int l, r, val;
} t[N << 2];
int n, m, ans[N];
void pushup(int p) {
t[p].val = min(t[ls].val, t[rs].val);
}
void build(int p, int l, int r) {
t[p].l = l, t[p].r = r, t[p].val = 0;
if(l == r) return ;
int mid = l + r >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
}
void find(int p, int k, int w, int dta) {
if(t[p].l == t[p].r) {
if(t[p].val <= k) {
ans[t[p].l] += w;
t[p].val = dta;
}
return ;
}
int mid = t[p].l + t[p].r >> 1;
if(t[ls].val <= k) find(ls, k, w, dta);
else find(rs, k, w, dta);
pushup(p);
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m;
build(1, 1, n);
For(i,1,m) {
int t, w, s;
cin >> t >> w >> s;
find(1, t, w, t + s);
}
For(i,1,n) cout << ans[i] << '\n';
return 0;
}
[ABC324E] Joint Two Strings#
很无聊的题。
先记录第
于是排序二分统计即可。
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 5e5 + 10;
struct Node {
int pre, nxt;
} a[N];
string t, s[N];
int n, ans;
vector<int> pre;
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> t;
For(i,1,n) {
cin >> s[i];
int k = 0;
for (int j = 0; j < s[i].size(); j++) {
if(s[i][j] == t[k]) k++;
}
a[i].pre = k;
pre.push_back(a[i].pre);
k = t.size()-1;
for (int j = s[i].size()-1; j >= 0; j--) {
if(s[i][j] == t[k]) k--;
}
a[i].nxt = t.size() - k - 1;
}
sort(pre.begin(), pre.end());
For(i,1,n) {
vector<int>::iterator x1;
x1 = lower_bound(pre.begin(), pre.end(), t.size()-a[i].nxt);
if(x1 != pre.end()) ans += (pre.size() - (x1 - pre.begin()));
}
cout << ans << '\n';
return 0;
}
[ABC325E] Our clients, please wait a moment#
分层图好题(可以当做模板)。
将图分层:第一层为坐汽车的图,第二层为坐火车的图,由于坐火车之后不能再坐汽车,所以将第一层的图向第二层的图连单向边,最后跑
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int D = 1e3 + 10, N = 1e5 + 10, M = 5e6 + 10;
struct Node {
int v, w, nx;
bool operator < (const Node &x) const {
return x.w < w;
}
} e[M];
int n, a, b, c, d[D][D], h[N], dis[N], tot;
bool st[N];
void add(int u, int v, int w) {
e[++tot] = (Node){v, w, h[u]};
h[u] = tot;
}
void dijk() {
priority_queue<Node> q;
q.push((Node){1, 0});
memset(dis, 0x3f, sizeof dis);
dis[1] = 0;
while(!q.empty()) {
int x = q.top().v;
q.pop();
if(st[x]) continue;
st[x] = 1;
for (int i = h[x]; i; i = e[i].nx) {
int y = e[i].v;
if(dis[y] > dis[x] + e[i].w) {
dis[y] = dis[x] + e[i].w;
if(!st[y]) q.push((Node){y, dis[y]});
}
}
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> a >> b >> c;
For(i,1,n) {
For(j,1,n) {
cin >> d[i][j];
}
}
For(i,1,n) {
add(i, i + n, 0);
For(j,1,i-1) {
add(i, j, d[i][j] * a);
add(j, i, d[i][j] * a);
add(i + n, j + n, d[i][j] * b + c);
add(j + n, i + n, d[i][j] * b + c);
}
}
dijk();
cout << min(dis[n], dis[n*2]) << '\n';
return 0;
}
[ABC327E] Maximize Rating#
dp 好题。
先拆贡献,
要求
- 选
: ; - 不选
: ;
两者取最大值即可。
预处理出
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
#define inf 1e9
using namespace std;
const int N = 5e3 + 10;
int n, a[N];
double ans = -inf, dp[N][N], sum[N];
signed main() {
// ios::sync_with_stdio(0);
// cin.tie(0), cout.tie(0);
cin >> n;
For(i,1,n) cin >> a[i];
For(i,1,n) {
For(j,1,i) {
dp[i][j] = max(dp[i-1][j], dp[i-1][j-1] * 0.9 + a[i]);
}
}
double pw = 1;
For(i,1,n) {
sum[i] = sum[i-1] + pw;
pw *= 0.9;
}
For(k,1,n) {
ans = max(ans, (1.0 * dp[n][k] / sum[k]) - 1200.0 / sqrt(k));
}
printf("%.15lf\n", ans);
return 0;
}
[ABC319E] Bus Stops#
思维题(性质题)。
可以发现
若出发时间为
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 2e5 + 10;
struct Node {
int t, p;
} a[N];
int n, x, y, q, ans[840];
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> x >> y;
For(i,1,n-1) cin >> a[i].p >> a[i].t;
For(i,0,839) {
int tim = i + x;
ans[i] = x;
For(j,1,n-1) {
while(tim % a[j].p != 0) tim++, ans[i]++;
tim += a[j].t, ans[i] += a[j].t;
}
ans[i] += y;
}
cin >> q;
while(q--) {
cin >> x;
cout << x + (ans[x % 840]) << '\n';
}
return 0;
}
[ABC328E] Modulo MST#
很无聊的题。
暴力搜索树边,一边搜索一边判是否有环即可。写一个带撤销的并查集维护,所以不能路径压缩。
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
#define inf 1e18
using namespace std;
const int N = 105;
struct Node {
int u, v, w;
} e[N];
int n, m, k, f[N], ans = inf;
int find(int x) {
return (x == f[x] ? x : find(f[x]));
}
void dfs(int x, int len, int num) {
if(len == n - 1) {
ans = min(ans, num);
return ;
}
For(i,x+1,m) {
int u = find(e[i].u), v = find(e[i].v);
if(u != v) {
f[u] = v;
dfs(i, len + 1, (num + e[i].w) % k);
f[u] = u;
}
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m >> k;
For(i,1,n) f[i] = i;
For(i,1,m) {
cin >> e[i].u >> e[i].v >> e[i].w;
}
dfs(0, 0, 0);
cout << ans << '\n';
return 0;
}
[ABC330E] Mex and Update#
很无聊的题。
动态维护全局
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
#define inf 1e9
using namespace std;
const int N = 2e5 + 10;
struct Node {
int ls, rs, val;
} t[N * 50];
int n, m, rt, a[N], idx;
void pushup(int p) {
t[p].val = min(t[t[p].ls].val, t[t[p].rs].val);
}
void upd(int &p, int l, int r, int x, int k) {
if(!p) p = ++idx;
if(l == r) {
t[p].val += k;
return ;
}
int mid = l + r >> 1;
if(x <= mid) upd(t[p].ls, l, mid, x, k);
else upd(t[p].rs, mid + 1, r, x, k);
pushup(p);
}
int Find(int &p, int l, int r) {
if(!p) p = ++idx;
if(l == r) return l;
int mid = l + r >> 1;
if(t[t[p].ls].val == 0) return Find(t[p].ls, l, mid);
else return Find(t[p].rs, mid + 1, r);
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m;
For(i,1,n) {
cin >> a[i]; upd(rt, 0, inf, a[i], 1);
}
while(m--) {
int x, k;
cin >> x >> k;
upd(rt, 0, inf, a[x], -1);
upd(rt, 0, inf, k, 1);
a[x] = k;
cout << Find(rt, 0, inf) << '\n';
}
return 0;
}
[ABC331E] Set Meal#
很好的数据结构题。
可以给限制按照主菜编号第一关键词,配菜编号第二关键词排序。维护
对于限制可以用指针扫,恢复修改操作即用数组存下来,统计完贡献之后再原封不动的改回去即可。
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define ls p<<1
#define rs p<<1|1
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 1e5 + 10;
struct node {
int x, y;
} q[N];
struct Node {
int l, r, val;
} t[N << 2];
int n, m, Q, a[N], b[N], c[N], ans;
bool cmp(node x, node y) {
return (x.x == y.x ? x.y < y.y : x.x < y.x);
}
void pushup(int p) {
t[p].val = max(t[ls].val, t[rs].val);
}
void build(int p, int l, int r) {
t[p].l = l, t[p].r = r;
if(l == r) {
t[p].val = b[l];
return ;
}
int mid = l + r >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
pushup(p);
}
void upd(int p, int x, int k) {
if(t[p].l == t[p].r) {
t[p].val = k;
return ;
}
int mid = t[p].l + t[p].r >> 1;
if(x <= mid) upd(ls, x, k);
else upd(rs, x, k);
pushup(p);
}
int qry(int p, int l, int r) {
if(l <= t[p].l && t[p].r <= r) {
return t[p].val;
}
int mid = t[p].l + t[p].r >> 1, ans = 0;
if(l <= mid) ans = max(ans, qry(ls, l, r));
if(r > mid) ans = max(ans, qry(rs, l, r));
return ans;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m >> Q;
For(i,1,n) cin >> a[i];
For(i,1,m) cin >> b[i];
build(1, 1, m);
For(i,1,Q) cin >> q[i].x >> q[i].y;
sort(q + 1, q + Q + 1, cmp);
int j = 1, last = 1;
For(i,1,n) {
last = j;
while(q[j].x == i && j <= Q) {
c[j] = qry(1, q[j].y, q[j].y);
upd(1, q[j].y, 0);
j++;
}
ans = max(ans, a[i] + qry(1, 1, m));
For(k,last,j-1) {
upd(1, q[k].y, c[k]);
}
}
cout << ans << '\n';
return 0;
}
[ABC333E] Takahashi Quest#
小思维题
考虑如何使怪物全部杀死的情况下药水最少,那就是需要打败
于是考虑逆序求解,用桶统计现在需要杀死那些怪物,然后捡起对应的药水。若当前没有需要杀死的
再顺序求出药水数量的最大值最小即可。
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 2e5 + 10;
struct Node {
int t, x;
} a[N];
int n, cnt[N], Ans, ans[N], len, num;
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
For(i,1,n) cin >> a[i].t >> a[i].x;
FOR(i,n,1) {
if(a[i].t == 1) {
if(cnt[a[i].x]) cnt[a[i].x]--, ans[++len] = 1;
else ans[++len] = 0;
} else {
cnt[a[i].x]++;
ans[++len] = -1;
}
}
For(i,1,n) {
if(cnt[i]) {
cout << "-1\n";
return 0;
}
}
FOR(i,len,1) {
if(ans[i] == 1) num++;
else if(ans[i] == -1) num--;
Ans = max(Ans, num);
}
cout << Ans << '\n';
FOR(i,len,1) {
if(ans[i] == -1) continue;
cout << ans[i] << ' ';
}
return 0;
}
[ABC334E] Christmas Color Grid 1#
有点无聊的题。
用并查集维护绿色节点。枚举 #
造成的贡献,即统计合并其上下左右节点后的连通块个数(保证
然后计算期望即可。
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
#define mod 998244353
using namespace std;
const int N = 1e3 + 10, M = 1e6 + 10;
const int dx[] = {0, 0, -1, 1};
const int dy[] = {-1, 1, 0, 0};
int n, m, ans1, ans2, Ans, cnt[M], f[M];
char a[N][N];
int id(int x, int y) {
return (x-1) * m + y;
}
int find(int x) {
return (x == f[x] ? x : f[x] = find(f[x]));
}
int qpow(int a, int b) {
int res = 1;
for (; b; b >>= 1, a = (a * a) % mod) {
if(b & 1) res = (res * a) % mod;
}
return res;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m;
For(i,1,n) {
For(j,1,m) f[id(i, j)] = id(i, j);
}
For(i,1,n) {
For(j,1,m) {
cin >> a[i][j];
if(a[i][j] == '.') ans2++;
else {
For(k,0,3) {
int nx = i + dx[k], ny = j + dy[k];
if(nx >= 1 && nx <= n && ny >= 1 && ny <= m && a[nx][ny] == '#') {
f[find(id(nx, ny))] = find(id(i, j));
}
}
}
}
}
For(i,1,n) {
For(j,1,m) {
if(a[i][j] == '#') {
if(!cnt[find(id(i, j))]) Ans++;
cnt[find(id(i, j))]++;
}
}
}
memset(cnt, 0, sizeof cnt);
For(i,1,n) {
For(j,1,m) {
if(a[i][j] == '.') {
int num = 0;
For(k,0,3) {
int nx = i + dx[k], ny = j + dy[k];
if(nx >= 1 && nx <= n && ny >= 1 && ny <= m && a[nx][ny] == '#') {
if(!cnt[find(id(nx, ny))]) num++;
cnt[find(id(nx, ny))]++;
num %= mod;
}
}
ans1 = (ans1 + (Ans - num + 1) % mod) % mod;
For(k,0,3) {
int nx = i + dx[k], ny = j + dy[k];
if(nx >= 1 && nx <= n && ny >= 1 && ny <= m && a[nx][ny] == '#') {
cnt[find(id(nx, ny))]--;
}
}
}
}
}
cout << (ans1 * qpow(ans2, mod-2)) % mod << '\n';
return 0;
}
[ABC337E] Bad Juice#
特别思维的好题。
最少的人数为
注意当
代码不难,重在构造的思维。
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 105;
int n, m, len, a[N];
char s[N];
vector<int> v;
signed main() {
cin >> n;
m = ceil(log2(n));
cout << m << endl;
For(i,0,m-1) {
vector<int>().swap(v);
For(j,1,n) {
if((j >> i) & 1) v.push_back(j);
}
cout << v.size() << ' ';
for (auto x : v) cout << x << ' ';
cout << endl;
}
cin >> (s + 1);
len = strlen(s + 1);
int ans = 0;
For(i,0,len-1) {
ans |= (1 << i) * (s[i+1] - '0');
}
if(!ans) ans = n;
cout << ans << '\n';
return 0;
}
[ABC321E] Complete Binary Tree#
思维题,同样没反应过来。
可以发现题目给出的连边关系构成的是一棵左偏二叉树(完美二叉树)。
考虑
对于
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
int T, n, x, k;
int F(int x, int k) {
if(k < 0) return 0;
int l = x, r = x;
For(i,1,k) {
l <<= 1, r = r << 1 | 1;
if(l > n) return 0;
}
return min(n, r) - l + 1;
}
void solve() {
cin >> n >> x >> k;
int ans = F(x, k);
while(x / 2) {
k--;
ans += F(x/2, k) - F(x, k-1);
x >>= 1;
}
cout << ans << '\n';
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> T;
while(T--) solve();
return 0;
}
[ABC322E] Product Development#
很无聊但是很好玩的题。
设
因为
答案即为
写出来有一种脑干缺失的美感。(乐)。
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
const int N = 105, M = 6;
struct Node {
int p[6];
} a[N];
int n, k, p, c[N], dp[N][M][M][M][M][M], lim[N], ans = inf;
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> k >> p;
For(i,1,n) {
cin >> c[i];
For(j,1,k) cin >> a[i].p[j];
}
memset(dp, 0x3f, sizeof dp);
dp[0][0][0][0][0][0] = 0;
For(i,1,k) lim[i] = p;
For(i,0,n-1) {
For(p1,0,lim[1]) {
For(p2,0,lim[2]) {
For(p3,0,lim[3]) {
For(p4,0,lim[4]) {
For(p5,0,lim[5]) {
dp[i+1][p1][p2][p3][p4][p5] = min(dp[i+1][p1][p2][p3][p4][p5], dp[i][p1][p2][p3][p4][p5]);
dp[i+1][min(lim[1],p1+a[i+1].p[1])][min(lim[2],p2+a[i+1].p[2])][min(lim[3],p3+a[i+1].p[3])][min(lim[4],p4+a[i+1].p[4])][min(lim[5],p5+a[i+1].p[5])] =
min(dp[i+1][min(lim[1],p1+a[i+1].p[1])][min(lim[2],p2+a[i+1].p[2])][min(lim[3],p3+a[i+1].p[3])][min(lim[4],p4+a[i+1].p[4])][min(lim[5],p5+a[i+1].p[5])],
dp[i][p1][p2][p3][p4][p5] + c[i+1]);
if(p1+a[i+1].p[1] >= lim[1] && p2+a[i+1].p[2] >= lim[2] && p3+a[i].p[3] >= lim[3] && p4+a[i+1].p[4] >= lim[4] && p5+a[i+1].p[5] >= lim[5]) {
ans = min(ans, dp[i][p1][p2][p3][p4][p5] + c[i+1]);
}
}
}
}
}
}
}
ans = dp[n][lim[1]][lim[2]][lim[3]][lim[4]][lim[5]];
cout << (ans == inf ? -1 : ans) << '\n';
return 0;
}
[ABC329E] Stamp#
考虑能看到的字符串,即给出的字符串
设
时,能够接着之前的进行匹配,即 ;也能新开一个进行匹配,即 ; 时,只能新开一个进行匹配,即 ;
答案即为
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 2e5 + 10;
int n, m, f[N][6];
char s[N], t[N];
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m;
cin >> (s + 1) >> (t + 1);
f[0][0] = 1;
For(i,1,n) {
For(j,1,m) {
if(s[i] == t[j]) f[i][j] |= (f[i-1][j-1] | f[i-1][m]);
if(s[i] == t[1]) f[i][1] |= f[i-1][j];
}
}
cout << (f[n][m] ? "Yes" : "No") << '\n';
return 0;
}
[ABC335E] Non-Decreasing Colorful Path#
有点意思的题。
考虑求解
但是会有一条边的两个点的点权相等的情况,这样就直接缩在一起就行了,用并查集合并即可。
然后就是 DAG 上
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 1e6 + 10;
struct Node {
int v, nx;
} e[N];
struct node {
int u, v;
} E[N];
int n, m, a[N], h[N], tot, f[N], in[N], dp[N];
int find(int x) {
return (x == f[x] ? x : f[x] = find(f[x]));
}
void add(int u, int v) {
e[++tot] = (Node){v, h[u]};
h[u] = tot;
}
void topu_sort() {
queue<int> q;
memset(dp, -0x3f, sizeof dp);
dp[find(1)] = 1;
For(i,1,n) if(!in[find(i)] && find(i) == i) {
q.push(find(i));
}
while(!q.empty()) {
int x = q.front();
q.pop();
for (int i = h[x]; i; i = e[i].nx) {
int y = e[i].v;
dp[y] = max(dp[y], dp[x] + 1);
if(!(--in[y])) {
q.push(y);
}
}
}
cout << max(0ll, dp[find(n)]) << '\n';
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m;
For(i,1,n) cin >> a[i], f[i] = i;
For(i,1,m) {
int u, v;
cin >> u >> v;
E[i] = (node){u, v};
if(a[u] == a[v]) {
f[find(u)] = find(v);
}
}
For(i,1,n) f[i] = find(i);
For(i,1,m) {
int u = E[i].u, v = E[i].v;
if(a[u] == a[v]) continue;
if(a[find(u)] > a[find(v)]) swap(u, v);
add(find(u), find(v));
in[find(v)]++;
}
topu_sort();
return 0;
}
[ABC338E] Chords#
有点意思的题。不过被秒了。
将圆上的点铺在数轴上,对于
先将线段按左端点排好序,右端点为第二关键字。然后从 set
亦可),支持插入与二分操作即可。(或者直接二分也可以)
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 2e5 + 10;
struct Node {
int l, r;
} a[N];
int n;
bool cmp(Node x, Node y) {
return (x.l == y.l ? x.r < y.r : x.l < y.l);
}
set<int> s;
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
For(i,1,n) cin >> a[i].l >> a[i].r;
For(i,1,n) {
if(a[i].l > a[i].r) swap(a[i].l, a[i].r);
}
sort(a + 1, a + n + 1, cmp);
For(i,1,n) {
int x = *(s.upper_bound(a[i].l));
if(a[i].l < x && x < a[i].r) {
cout << "Yes\n"; return 0;
}
s.insert(a[i].r);
}
cout << "No\n";
return 0;
}
[ABC326E] Revenge of "The Salary of AtCoder Inc."#
在期望题中算简单题,但是我不会期望。
设
对于
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
#define mod 998244353
using namespace std;
const int N = 3e5 + 10;
int n, a[N], sum = 1, ans;
int qpow(int a, int b) {
int res = 1;
for (; b; b >>= 1, a = (a * a) % mod) {
if(b & 1) res = (res * a) % mod;
}
return res;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
For(i,1,n) cin >> a[i];
sum = qpow(n, mod-2);
For(i,1,n) {
ans = (ans + a[i] * sum) % mod;
sum = (sum + (qpow(n, mod-2) * sum) % mod) % mod;
}
cout << ans << '\n';
return 0;
}
[ABC312E] Tangency of Cuboids#
人类智慧题。
由于长方体无交,所以它们所在的方格系统中每一个方格最多属于一个长方体。对于一个长方体中某一个格子,它
可以对长方体所在格子暴力染色(由于无交,每个格子最多会被扫到一次,时间复杂度 set
维护,统计答案同时去重。
总时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 1e5 + 10, M = 105;
const int dx[3] = {0, 0, 1}, dy[3] = {0, 1, 0}, dz[3] = {1, 0, 0};
int n, a[M][M][M];
set<int> s[N];
signed main() {
cin >> n;
For(i,1,n) {
int x1, x2, y1, y2, z1, z2;
cin >> x1 >> y1 >> z1 >> x2 >> y2 >> z2;
For(x,x1+1,x2) {
For(y,y1+1,y2) {
For(z,z1+1,z2) {
a[x][y][z] = i;
}
}
}
}
For(x,1,100) {
For(y,1,100) {
For(z,1,100) {
For(i,0,2) {
int nx = x + dx[i], ny = y + dy[i], nz = z + dz[i];
if(a[x][y][z] && a[nx][ny][nz] && a[x][y][z] != a[nx][ny][nz]) {
s[a[x][y][z]].insert(a[nx][ny][nz]);
s[a[nx][ny][nz]].insert(a[x][y][z]);
}
}
}
}
}
For(i,1,n) cout << s[i].size() << '\n';
return 0;
}
[ABC332E] Lucky bag#
一眼看不出来的简单题。
可以看看贡献的真正面目是怎么样的:
只要最小化
然后开始状压
答案即为
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 20;
int n, d, w[N], s[1<<N], dp[N][1<<N];
signed main() {
cin >> n >> d;
For(i,0,n-1) {
cin >> w[i];
For(j,0,(1<<n)-1) {
if((j >> i) & 1) s[j] += w[i];
}
}
For(i,0,(1<<n)-1) s[i] *= s[i], dp[0][i] = 1e18;
dp[0][0] = 0;
For(i,1,d) {
For(S,0,(1<<n)-1) {
dp[i][S] = s[S];
for (int j = S; j; j = S & (j - 1)) {
dp[i][S] = min(dp[i][S], dp[i-1][j] + s[S ^ j]);
}
}
}
printf("%.15lf", 1.0*(dp[d][(1<<n)-1] * d - s[(1<<n)-1]) / (d * d));
return 0;
}
[ABC348F] Oddly Similar#
垃圾题。暴力
点击查看代码
#pragma GCC optimize(3)
#pragma GCC target("avx")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#include<bits/stdc++.h>
#define int long long
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
using namespace std;
const int N = 2e3 + 10;
int n, m, a[N][N], ans;
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m;
For(i,1,n) For(j,1,m) cin >> a[i][j];
For(i,1,n) {
For(j,1,i-1) {
int num = 0;
For(k,1,m) {
num += (a[i][k] == a[j][k]);
}
if(num & 1) ans++;
}
}
cout << ans << '\n';
return 0;
}
[ABC321F] #(subset sum = K) with Add and Erase#
有点意思的题。
可以发现没有删除操作就是一个
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
#define mod 998244353
using namespace std;
const int N = 5e3 + 10;
int n, q, dp[N][N];
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> q >> n;
dp[0][0] = 1;
For(i,1,q) {
char op; int x;
cin >> op >> x;
if(op == '+') {
For(j,0,n) {
dp[i][j] = dp[i-1][j];
if(j-x >= 0) dp[i][j] = (dp[i][j] + dp[i-1][j-x]) % mod;
}
} else {
For(j,0,n) dp[i][j] = dp[i-1][j];
For(j,0,n) if(j+x <= n && dp[i][j+x] && dp[i][j]) dp[i][j+x] = (dp[i][j+x] - dp[i][j] + mod) % mod;
}
cout << dp[i][n] << '\n';
}
return 0;
}
[ABC329F] Colored Ball#
很无聊的题,但是没想清楚。
启发式合并,重点在如果 swap
两个 set
就可以了(这一点没有想到难崩)。
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 2e5 + 10;
int n, q, a[N];
set<int> s[N];
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> q;
For(i,1,n) cin >> a[i], s[i].insert(a[i]);
while(q--) {
int x, y;
cin >> x >> y;
if(s[x].size() < s[y].size()) {
for (auto i : s[x]) s[y].insert(i);
set<int>().swap(s[x]);
} else {
for (auto i : s[y]) s[x].insert(i);
set<int>().swap(s[y]);
swap(s[x], s[y]);
}
cout << s[y].size() << '\n';
}
return 0;
}
[ABC312F] Cans and Openers#
有意思的贪心题。
将物品按照类型分类之后从大到小排序,先算出全选普通罐头的贡献。然后枚举选几个普通罐头,对应的可以用二分求出最小需要几个开罐器,然后对应的拉环罐头的个数也就定下来了。
最后将所有的情况的贡献取最大即可。注意,拉环罐头的个数可能在枚举时定为了负数或者超过了全部拉环罐头的个数。这时候需要判断一下边界并注意一下细节。
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 2e5 + 10;
int n, m, n1, n2, n3, a[N], b[N], c[N], sum1[N], sum2[N], sum3[N], ans;
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m;
For(i,1,n) {
int op, x;
cin >> op >> x;
if(op == 0) {
a[++n1] = x;
} else if(op == 1) {
b[++n2] = x;
} else {
c[++n3] = x;
}
}
sort(a + 1, a + n1 + 1, [](int x, int y){return x > y;});
sort(b + 1, b + n2 + 1, [](int x, int y){return x > y;});
sort(c + 1, c + n3 + 1, [](int x, int y){return x > y;});
For(i,1,n1) sum1[i] = sum1[i-1] + a[i];
For(i,1,n2) sum2[i] = sum2[i-1] + b[i];
For(i,1,n3) sum3[i] = sum3[i-1] + c[i];
ans = (n1 == 0 ? 0 : sum1[min(m, n1)]);
For(i,1,n2) {
int l = 1, r = n3, p = -1;
while(l <= r) {
int mid = l + r >> 1;
if(sum3[mid] >= i) {
p = mid;
r = mid - 1;
} else {
l = mid + 1;
}
}
if(p == -1) continue;
if(m - p - i >= 0) ans = max(ans, sum1[min(m - p - i, n1)] + sum2[i]);
}
cout << ans << '\n';
return 0;
}
[ABC315F] Shortcuts#
有意思的
首先可以设
转移显然为:
看似这个
所以实际上时间复杂度为
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int M = 31, N = 1e4 + 10;
struct Node {
int x, y;
} a[N];
int n;
long double dp[N][M], ans = 1e10;
long double dis(int i, int j) {
return sqrt((a[i].x - a[j].x) * (a[i].x - a[j].x) + (a[i].y - a[j].y) * (a[i].y - a[j].y));
}
int qpow(int a, int b) {
if(b < 0) return 0;
int res = 1;
for (; b; b >>= 1, a = a * a) {
if(b & 1) res = res * a;
}
return res;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
For(i,1,n) For(j,0,30) dp[i][j] = 1e10;
dp[1][0] = 0;
For(i,1,n) cin >> a[i].x >> a[i].y;
For(i,2,n) {
For(j,max(1ll,i-30),i-1) {
For(k,0,30) {
if(k >= (i-j-1)) dp[i][k] = min(dp[i][k], dp[j][k-(i-j-1)] + dis(i, j));
}
}
}
For(k,0,30) ans = min(ans, dp[n][k] + qpow(2, k-1));
printf("%.20Lf\n", ans);
return 0;
}
[ABC322F] Vacation Query#
很有意思的数据结构题。
用线段树维护节点区间
pushup
:合并两个子节点的信息,即前缀信息可以由左儿子的前缀或者左儿子整段加右儿子前缀构成,后缀信息可以由右儿子的后缀或者右儿子整段加左儿子后缀构成。最后再把最长连续 的长度由左儿子最长连续 的长度和右儿子最长连续 的长度和左右儿子的前后缀拼接而成更新。- 区间翻转:打一个翻转标记,翻转时关于
的信息和关于 的信息交换。 - 区间查询:先找出所有的包含于查询区间的节点区间,在分别在它们的
合并即可。
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define ls p<<1
#define rs p<<1|1
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
#define inf 100000000
using namespace std;
const int N = 5e5 + 10;
struct Node {
int l, r;
int pre[2], suf[2];
int val[2];
int tag;
} t[N << 2];
int n, m;
char s[N];
void pushup(int p) {
For(i,0,1) {
t[p].val[i] = max({t[ls].val[i], t[rs].val[i], t[ls].suf[i] + t[rs].pre[i]});
t[p].pre[i] = max(t[ls].pre[i], (t[ls].val[i] != t[ls].r - t[ls].l + 1 ? -inf : t[ls].val[i] + t[rs].pre[i]));
t[p].suf[i] = max(t[rs].suf[i], (t[rs].val[i] != t[rs].r - t[rs].l + 1 ? -inf : t[rs].val[i] + t[ls].suf[i]));
}
}
void pushdown(int p) {
if(t[p].tag) {
swap(t[ls].val[0], t[ls].val[1]);swap(t[ls].pre[0], t[ls].pre[1]);swap(t[ls].suf[0], t[ls].suf[1]);
swap(t[rs].val[0], t[rs].val[1]);swap(t[rs].pre[0], t[rs].pre[1]);swap(t[rs].suf[0], t[rs].suf[1]);
t[ls].tag ^= 1;
t[rs].tag ^= 1;
t[p].tag = 0;
return ;
}
}
void build(int p, int l, int r) {
t[p].l = l, t[p].r = r, t[p].tag = 0;
if(l == r) {
t[p].val[s[l]-'0']++;
t[p].pre[s[l]-'0']++;
t[p].suf[s[l]-'0']++;
return ;
}
int mid = l + r >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
pushup(p);
}
void upd(int p, int l, int r) {
if(l <= t[p].l && t[p].r <= r) {
swap(t[p].val[0], t[p].val[1]);
swap(t[p].pre[0], t[p].pre[1]);
swap(t[p].suf[0], t[p].suf[1]);
t[p].tag ^= 1;
return ;
}
pushdown(p);
int mid = t[p].l + t[p].r >> 1;
if(l <= mid) upd(ls, l, r);
if(r > mid) upd(rs, l, r);
pushup(p);
}
Node qry(int p, int l, int r) {
if(l <= t[p].l && t[p].r <= r) {
return t[p];
}
pushdown(p);
int mid = t[p].l + t[p].r >> 1;
Node ans;
if(l <= mid && mid < r) {
Node Ls = qry(ls, l, r), Rs = qry(rs, l, r);
For(i,0,1) {
ans.val[i] = max({Ls.val[i], Rs.val[i], Ls.suf[i] + Rs.pre[i]});
ans.pre[i] = max(Ls.pre[i], (Ls.val[i] != Ls.r - Ls.l + 1 ? -inf : Ls.val[i] + Rs.pre[i]));
ans.suf[i] = max(Rs.suf[i], (Rs.val[i] != Rs.r - Rs.l + 1 ? -inf : Rs.val[i] + Ls.suf[i]));
}
return ans;
} else if(l <= mid) {
return qry(ls, l, r);
} else if(r > mid) {
return qry(rs, l, r);
}
return ans;
}
signed main() {
cin >> n >> m >> (s + 1);
build(1, 1, n);
while(m--) {
int op, l, r;
cin >> op >> l >> r;
if(op == 1) {
upd(1, l, r);
} else {
cout << qry(1, l, r).val[1] << '\n';
}
}
return 0;
}
[ABC324F] Beautiful Path#
板的
二分答案
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
#define eps 1e-10
#define inf 1e10
using namespace std;
const int N = 2e5 + 10;
struct Node {
int u, v;
long double a, b;
} e[N << 1];
int n, m;
long double dp[N], l, r;
bool cmp(Node x, Node y) {
return (x.u == y.u ? x.v < y.v : x.u < y.u);
}
bool check(long double x) {
For(i,1,n) dp[i] = -inf;
dp[1] = 0;
For(i,1,m) {
dp[e[i].v] = max(dp[e[i].v], dp[e[i].u] + (e[i].a - x * e[i].b));
}
return dp[n] > 0;
}
signed main() {
cin >> n >> m;
For(i,1,m) cin >> e[i].u >> e[i].v >> e[i].a >> e[i].b;
sort(e + 1, e + m + 1, cmp);
l = 0, r = 1e4;
while(r - l > eps) {
long double mid = (l + r) / 2;
if(check(mid)) {
l = mid;
} else {
r = mid;
}
}
printf("%.10Lf\n", l);
return 0;
}
[ABC323F] Push and Carry#
按照箱子和终点的位置分类讨论。注意一些细节即可。
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
struct Node {
int x, y;
} st, ed, box;
int dis(int x1, int y1, int x2, int y2) {
return (abs(x1 - x2) + abs(y1 - y2));
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> st.x >> st.y >> box.x >> box.y >> ed.x >> ed.y;
if(ed.x <= box.x && ed.y >= box.y) {
int ans1 = dis(st.x, st.y, box.x, box.y-1) + ((st.x == box.x && st.y > box.y) ? 2 : 0), ans2 = dis(st.x, st.y, box.x+1, box.y) + ((st.y == box.y && st.x < box.x) ? 2 : 0);
cout << min(ans1 + (ed.x == box.x ? 0 : 2), ans2 + (ed.y == box.y ? 0 : 2)) + dis(box.x, box.y, ed.x, ed.y) << '\n';
} else if(ed.x <= box.x && ed.y <= box.y) {
int ans1 = dis(st.x, st.y, box.x, box.y+1) + ((st.x == box.x && st.y < box.y) ? 2 : 0), ans2 = dis(st.x, st.y, box.x+1, box.y) + ((st.y == box.y && st.x < box.x) ? 2 : 0);
cout << min(ans1 + (ed.x == box.x ? 0 : 2), ans2 + (ed.y == box.y ? 0 : 2)) + dis(box.x, box.y, ed.x, ed.y) << '\n';
} else if(ed.x >= box.x && ed.y >= box.y) {
int ans1 = dis(st.x, st.y, box.x, box.y-1) + ((st.x == box.x && st.y > box.y) ? 2 : 0), ans2 = dis(st.x, st.y, box.x-1, box.y) + ((st.y == box.y && st.x > box.x) ? 2 : 0);
cout << min(ans1 + (ed.x == box.x ? 0 : 2), ans2 + (ed.y == box.y ? 0 : 2)) + dis(box.x, box.y, ed.x, ed.y) << '\n';
} else if(ed.x >= box.x && ed.y <= box.y) {
int ans1 = dis(st.x, st.y, box.x, box.y+1) + ((st.x == box.x && st.y < box.y) ? 2 : 0), ans2 = dis(st.x, st.y, box.x-1, box.y) + ((st.y == box.y && st.x > box.x) ? 2 : 0);
cout << min(ans1 + (ed.x == box.x ? 0 : 2), ans2 + (ed.y == box.y ? 0 : 2)) + dis(box.x, box.y, ed.x, ed.y) << '\n';
}
return 0;
}
[ABC338F] Negative Traveling Salesman#
有点意思的题。
初始化
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
#define inf 1e10
using namespace std;
const int N = 21;
int n, m, dp[N][1<<N], f[N][N], ans = inf;
void floyd() {
For(k,1,n) {
For(i,1,n) {
For(j,1,n) {
f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
}
}
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m;
memset(f, 0x3f, sizeof f);
memset(dp, 0x3f, sizeof dp);
For(i,1,m) {
int u, v, w;
cin >> u >> v >> w;
f[u][v] = w;
}
floyd();
For(i,1,n) dp[i][1<<(i-1)] = 0;
For(S,0,(1<<n)-1) {
For(i,1,n) {
if(((S >> (i-1)) & 1)) {
For(j,1,n) {
if(((S >> (j-1)) & 1) || i == j) {
dp[i][S] = min(dp[i][S], dp[j][S ^ (1 << (i-1))] + f[j][i]);
}
}
}
}
}
For(i,1,n) ans = min(ans, dp[i][(1<<n)-1]);
if(ans == inf) cout << "No\n";
else cout << ans << '\n';
return 0;
}
[ABC326F] Robot Rotation#
很好想但很难调的题。
首先有个性质:
分开来看之后,操作序列的长度已经 map
记录
最后是统计答案,记录一个方位标记,围绕方位和顺逆时针讨论即可。
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 105;
int n, X[2], a[N], a1[N], a2[N], len[2], Ans[2];
char ans[N];
map<int, int> mp;
bool solve(int op) {
map<int, int>().swap(mp);
int m = len[op] / 2;
mp[0] = 0;
For(S,0,(1<<m)-1) {
int res = 0;
For(i,1,m) {
res += (((S >> (i-1)) & 1) ? 1 : -1) * (op == 0 ? a1[i] : a2[i]);
}
mp[res] = S;
}
For(S,0,(1<<(len[op]-m))-1) {
int res = 0;
For(i,m+1,len[op]) {
res += (((S >> (i-m-1)) & 1) ? 1 : -1) * (op == 0 ? a1[i] : a2[i]);
}
if(mp.count(X[op] - res)) {
Ans[op] = (S << m) + mp[X[op] - res];
return 1;
}
}
return 0;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> X[1] >> X[0];
For(i,1,n) cin >> a[i];
For(i,1,n) {
if(i & 1) a1[++len[0]] = a[i];
else a2[++len[1]] = a[i];
}
if(solve(0) && solve(1)) {
cout << "Yes\n";
int dist = 0;
For(i,1,n) {
int p = (i - 1) / 2;
if(i & 1) {
if((Ans[0] >> p) & 1) {
cout << (dist == 0 ? "L" : "R"); dist = 3;
} else {
cout << (dist == 0 ? "R" : "L"); dist = 1;
}
} else {
if((Ans[1] >> p) & 1) {
cout << (dist == 3 ? "R" : "L"); dist = 0;
} else {
cout << (dist == 3 ? "L" : "R"); dist = 2;
}
}
}
} else {
cout << "No\n";
}
return 0;
}
[ABC339F] Product Equality#
一眼 map
维护,两眼
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
#define mod 19491001
#define mod2 998244853
#define mk make_pair
using namespace std;
const int N = 1e3 + 10;
string s[N];
int n, a[N], b[N], ans;
map<pair<int, int>, int> mp;
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
For(i,1,n) cin >> s[i];
For(i,1,n) {
for (int j = 0; j < s[i].size(); ++j) {
a[i] = ((a[i] * 10) % mod + (s[i][j] - '0')) % mod;
b[i] = ((b[i] * 10) % mod2 + (s[i][j] - '0')) % mod2;
}
mp[mk(a[i], b[i])]++;
}
For(i,1,n) {
For(j,1,n) {
ans += mp[mk((a[i] * a[j]) % mod, (b[i] * b[j]) % mod2)];
}
}
cout << ans << '\n';
return 0;
}
[ABC350F] Transpose#
很无聊的数据结构题。
用栈处理翻转关系,然后用文艺平衡树维护翻转即可。
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 5e5 + 10;
struct Node {
int l, r, val, key, siz, tag;
} t[N];
int n, stk[N], top, root, sum[N], idx;
char s[N];
int x, y, z;
mt19937 rd(114514);
int New(int val) {
t[++idx] = (Node){0, 0, val, rd(), 1, 0};
return idx;
}
void pushup(int p) {
t[p].siz = t[t[p].l].siz + t[t[p].r].siz + 1;
}
void pushdown(int p) {
if(t[p].tag) {
swap(t[p].l, t[p].r);
t[t[p].l].tag ^= 1;
t[t[p].r].tag ^= 1;
t[p].tag = 0;
return ;
}
}
void split(int p, int k, int &x, int &y) {
if(!p) {x = y = 0; return ;}
pushdown(p);
if(k > t[t[p].l].siz) {
k -= (t[t[p].l].siz + 1);
x = p;
split(t[p].r, k, t[p].r, y);
} else {
y = p;
split(t[p].l, k, x, t[p].l);
}
pushup(p);
return ;
}
int merge(int x, int y) {
if(!x || !y) return x | y;
if(t[x].key < t[y].key) {
pushdown(x);
t[x].r = merge(t[x].r, y);
pushup(x);
return x;
} else {
pushdown(y);
t[y].l = merge(x, t[y].l);
pushup(y);
return y;
}
}
void print(int p) {
if(!p) return ;
pushdown(p);
print(t[p].l);
if(s[t[p].val] != '(' && s[t[p].val] != ')') cout << s[t[p].val];
print(t[p].r);
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> (s + 1);
n = strlen(s + 1);
For(i,1,n) root = merge(root, New(i));
For(i,1,n) {
if(s[i] == '(') stk[++top] = i;
else if(s[i] == ')') {
int l = stk[top--];
sum[l]++, sum[i+1]--;
split(root, i, x, z);
split(x, l-1, x, y);
t[y].tag ^= 1;
root = merge(x, merge(y, z));
}
}
For(i,1,n) {
sum[i] += sum[i-1];
if(sum[i] & 1) {
if(s[i] >= 'a' && s[i] <= 'z') s[i] += ('A' - 'a');
else if(s[i] >= 'A' && s[i] <= 'Z') s[i] += ('a' - 'A');
}
}
print(root);
return 0;
}
[ABC325F] Sensor Optimization Dilemma#
很小清新的 dp 题。
设
答案即为
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
#define inf 1e18
using namespace std;
const int N = 1e3 + 10;
int n, d[N], l[2], c[2], K[2], dp[N][N], ans = inf;
int Ceil(int x, int y) {
return (x - 1 + y) / y;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
For(i,1,n) cin >> d[i];
For(i,0,1) cin >> l[i] >> c[i] >> K[i];
memset(dp, 0x3f, sizeof dp);
dp[0][0] = 0;
For(i,1,n) {
For(j,0,K[0]) {
For(k,0,j) {
dp[i][j] = min(dp[i][j], dp[i-1][j-k] + Ceil(max(0ll, d[i] - k * l[0]), l[1]));
}
}
}
For(i,0,K[0]) {
if(dp[n][i] <= K[1])
ans = min(ans, i * c[0] + dp[n][i] * c[1]);
}
cout << (ans == inf ? -1 : ans) << '\n';
return 0;
}
[ABC357F] Two Sequence Queries#
无聊题。
线段树维护
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define ls p<<1
#define rs p<<1|1
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
#define mod 998244353
using namespace std;
const int N = 2e5 + 10;
struct Node {
int l, r, val, a, b, tag[2];
} t[N << 2];
int n, m, a[N], b[N];
void pushup(int p) {
t[p].val = (t[ls].val + t[rs].val) % mod;
t[p].a = (t[ls].a + t[rs].a) % mod;
t[p].b = (t[ls].b + t[rs].b) % mod;
}
void pushdown(int p) {
if(t[p].tag[0]) {
t[ls].val = (t[ls].val + (t[p].tag[0] * t[ls].b) % mod) % mod;
t[rs].val = (t[rs].val + (t[p].tag[0] * t[rs].b) % mod) % mod;
t[ls].a = (t[ls].a + (t[p].tag[0] * (t[ls].r - t[ls].l + 1)) % mod) % mod;
t[rs].a = (t[rs].a + (t[p].tag[0] * (t[rs].r - t[rs].l + 1)) % mod) % mod;
t[ls].tag[0] = (t[ls].tag[0] + t[p].tag[0]) % mod;
t[rs].tag[0] = (t[rs].tag[0] + t[p].tag[0]) % mod;
t[p].tag[0] = 0;
}
if(t[p].tag[1]) {
t[ls].val = (t[ls].val + (t[p].tag[1] * t[ls].a) % mod) % mod;
t[rs].val = (t[rs].val + (t[p].tag[1] * t[rs].a) % mod) % mod;
t[ls].b = (t[ls].b + (t[p].tag[1] * (t[ls].r - t[ls].l + 1)) % mod) % mod;
t[rs].b = (t[rs].b + (t[p].tag[1] * (t[rs].r - t[rs].l + 1)) % mod) % mod;
t[ls].tag[1] = (t[ls].tag[1] + t[p].tag[1]) % mod;
t[rs].tag[1] = (t[rs].tag[1] + t[p].tag[1]) % mod;
t[p].tag[1] = 0;
}
return ;
}
void build(int p, int l, int r) {
t[p].l = l, t[p].r = r;
if(l == r) {
t[p].val = (a[l] * b[l]) % mod;
t[p].a = a[l] % mod;
t[p].b = b[l] % mod;
return ;
}
int mid = l + r >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
pushup(p);
}
void upd(int p, int l, int r, int k, int op) {
if(l <= t[p].l && t[p].r <= r) {
if(!op) {
t[p].val = (t[p].val + (k * t[p].b) % mod) % mod;
t[p].a = (t[p].a + (k * (t[p].r - t[p].l + 1)) % mod) % mod;
} else {
t[p].val = (t[p].val + (k * t[p].a) % mod) % mod;
t[p].b = (t[p].b + (k * (t[p].r - t[p].l + 1)) % mod) % mod;
}
t[p].tag[op] = (t[p].tag[op] + k % mod) % mod;
return ;
}
pushdown(p);
int mid = t[p].l + t[p].r >> 1;
if(l <= mid) upd(ls, l, r, k, op);
if(r > mid) upd(rs, l, r, k, op);
pushup(p);
}
int qry(int p, int l, int r) {
if(l <= t[p].l && t[p].r <= r) {
return t[p].val;
}
pushdown(p);
int mid = t[p].l + t[p].r >> 1, ans = 0;
if(l <= mid) ans = (ans + qry(ls, l, r) % mod) % mod;
if(r > mid) ans = (ans + qry(rs, l, r) % mod) % mod;
return ans;
}
signed main() {
cin >> n >> m;
For(i,1,n) cin >> a[i];
For(i,1,n) cin >> b[i];
build(1, 1, n);
while(m--) {
int op, l, r, x;
cin >> op >> l >> r;
if(op == 1) {
cin >> x;
upd(1, l, r, x, 0);
} else if(op == 2) {
cin >> x;
upd(1, l, r, x, 1);
} else {
cout << qry(1, l, r) << '\n';
}
}
return 0;
}
[ABC327F] Apples#
无聊题。
考虑转化题意。给定平面直角坐标系内的
然后横坐标升序排序双指针维护,纵坐标线段树维护
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define ls p<<1
#define rs p<<1|1
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
#define inf 3e5
using namespace std;
const int N = 1e6 + 10;
struct node {
int l, r, val, tag;
} t[N << 2];
struct Node {
int x, y;
} a[N];
int n, d, w, ans = 0;
bool cmp(Node x, Node y) {
return (x.x == y.x ? x.y < y.y : x.x < y.x);
}
void pushup(int p) {
t[p].val = max(t[ls].val, t[rs].val);
}
void pushdown(int p) {
if(t[p].tag) {
t[ls].val += t[p].tag;
t[rs].val += t[p].tag;
t[ls].tag += t[p].tag;
t[rs].tag += t[p].tag;
t[p].tag = 0;
return ;
}
}
void build(int p, int l, int r) {
t[p].l = l, t[p].r = r, t[p].tag = t[p].val = 0;
if(l == r) return ;
int mid = l + r >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
pushup(p);
}
void upd(int p, int l, int r, int k) {
if(l <= t[p].l && t[p].r <= r) {
t[p].val += k;
t[p].tag += k;
return ;
}
pushdown(p);
int mid = t[p].l + t[p].r >> 1;
if(l <= mid) upd(ls, l, r, k);
if(r > mid) upd(rs, l, r, k);
pushup(p);
}
int qry(int p, int l, int r) {
if(l <= t[p].l && t[p].r <= r) {
return t[p].val;
}
pushdown(p);
int mid = t[p].l + t[p].r >> 1, ans = 0;
if(l <= mid) ans = max(ans, qry(ls, l, r));
if(r > mid) ans = max(ans, qry(rs, l, r));
return ans;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> d >> w;
For(i,1,n) cin >> a[i].x >> a[i].y;
build(1, 1, inf);
sort(a + 1, a + n + 1, cmp);
int r = 1;
For(l,1,n) {
while(a[r].x - a[l].x + 1 <= d && r <= n) {
upd(1, a[r].y - w + 1, a[r].y, 1);
ans = max(ans, qry(1, 1, inf));
r++;
}
upd(1, a[l].y - w + 1, a[l].y, -1);
}
cout << ans << '\n';
return 0;
}
[ABC311F] Yet Another Grid Task#
很性质的 dp 题。
首先可以知道如果一个点是黑点,那么它的下面和右下的点一定要是黑点,故按照此规则,设
则转移为:
前缀和优化做完,时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
#define mod 998244353
using namespace std;
const int N = 2e3 + 10;
int n, m, h[N], dp[N][N], sum[N][N];
char a[N][N];
signed main() {
cin >> n >> m;
For(i,1,n) For(j,1,m) cin >> a[i][j];
For(j,1,m) {
For(i,1,n) {
if(a[i][j] == '#') {
h[j] = n - i + 1;
break;
}
}
}
dp[0][0] = 1;
For(i,1,m) {
For(j,0,n+1) sum[i][j] = ((j == 0 ? 0 : sum[i][j-1]) + dp[i-1][j]) % mod;
For(j,h[i],n) {
dp[i][j] = (dp[i][j] + sum[i][j+1]) % mod;
}
}
int ans = 0;
For(i,h[m],n) ans = (ans + dp[m][i]) % mod;
cout << ans << '\n';
return 0;
}
[ABC345F] Many Lamps#
有点思维的题。
可以发现一条边操作无非三种贡献:
和 都是亮的,全部变成了暗的,此时状态贡献 ; 和 都是暗的,全部变成了亮的,此时状态贡献 ; 和 一亮一暗,还是变成一亮一暗,此时状态贡献不变;
每一次贡献都是偶数,所以
考虑如何构造方案。可以领出一个生成树。按照如下方式构造:
- 选出生成树的任意一个点
及其儿子 ,若 暗着,则操作该边。 - 然后在生成树中删除该边。
发现这样贡献要么贡献不变,要么贡献
时间复杂度 map
记录了一个边的编号)。
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 2e5 + 10;
struct Node {
int v, nx;
} e[N << 2];
int n, m, h[N], tot, cnt, k, tag[N];
vector<int> ans;
bool vis[N];
map<int, int> E[N];
void add(int u, int v) {
e[++tot] = (Node){v, h[u]};
h[u] = tot;
}
void dfs(int x) {
vis[x] = 1;
for (int i = h[x]; i; i = e[i].nx) {
int y = e[i].v;
if(vis[y]) continue;
dfs(y);
if(cnt < k && !tag[y]) {
cnt -= (tag[y] + tag[x]);
tag[y] ^= 1, tag[x] ^= 1;
cnt += (tag[y] + tag[x]);
ans.push_back(E[x][y]);
}
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m >> k;
For(i,1,m) {
int u, v;
cin >> u >> v;
add(u, v); add(v, u);
E[u][v] = E[v][u] = i;
}
For(i,1,n) if(!vis[i]) dfs(i);
if(cnt != k) cout << "No\n";
else {
cout << "Yes\n";
cout << ans.size() << '\n';
for (auto x : ans) cout << x << ' ';
cout << '\n';
}
return 0;
}
[ABC341F] Breakdown#
一个很有意思的思维题。
首先可以按照限制
然后对于限制
时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define For(i,l,r) for(int i=l;i<=r;++i)
#define FOR(i,r,l) for(int i=r;i>=l;--i)
using namespace std;
const int N = 1e6 + 10;
struct Node {
int v, u, nx;
} e[N], E[N];
int n, m, tot, h[N], w[N], a[N], in[N], f[N], dp[N], ans;
bool vis[N];
void add(int u, int v) {
e[++tot] = (Node){v, u, h[u]};
h[u] = tot;
in[v]++;
}
void dfs(int x) {
if(vis[x]) return ;
for (int i = h[x]; i; i = e[i].nx) {
int y = e[i].v;
dfs(y);
}
vis[x] = 1;
memset(dp, 0, sizeof dp);
for (int i = h[x]; i; i = e[i].nx) {
int y = e[i].v;
FOR(j,w[x]-1,w[y]) dp[j] = max(dp[j], dp[j - w[y]] + f[y]);
}
f[x] = dp[w[x]-1] + 1;
return ;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m;
For(i,1,m) cin >> E[i].u >> E[i].v;
For(i,1,n) cin >> w[i];
For(i,1,n) cin >> a[i];
For(i,1,m) {
int u = E[i].u, v = E[i].v;
if(w[u] < w[v]) add(v, u);
else if(w[u] > w[v]) add(u, v);
}
For(i,1,n) if(!in[i]) dfs(i);
For(i,1,n) ans += f[i] * a[i];
cout << ans << '\n';
return 0;
}
作者:Daniel-yao
出处:https://www.cnblogs.com/Daniel-yao/p/18343726
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!