AtCoder Beginner Contest 439
个人题解
Nanami^2 Even in the rain.
2026年01月03日
预计阅读 10 分钟
1975 字
A
#include<bits/stdc++.h>using namespace std;typedef long long ll;typedef unsigned long long ull;typedef pair<int,int> PII;#define MP make_pair#define fi first#define se second#define pb push_back#define eb emplace_back#define SET(a,b) memset(a,b,sizeof(a))#define CPY(a,b) memcpy(a,b,sizeof(b))#define rep(i,j,k) for(int i=(j);i<=(k);++i)#define per(i,j,k) for(int i=(j);i>=(k);--i)int read() { int a=0, f=1; char c=getchar(); while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); } while(isdigit(c)) a=a*10+c-'0', c=getchar(); return a*f;}signed main() { // ios::sync_with_stdio(0); // cin.tie(0); // cout.tie(0); int n; cin >> n; cout << (1ll << n) - 2 * n << endl; return 0;}B
#include<bits/stdc++.h>using namespace std;typedef long long ll;typedef unsigned long long ull;typedef pair<int,int> PII;#define MP make_pair#define fi first#define se second#define pb push_back#define eb emplace_back#define SET(a,b) memset(a,b,sizeof(a))#define CPY(a,b) memcpy(a,b,sizeof(b))#define rep(i,j,k) for(int i=(j);i<=(k);++i)#define per(i,j,k) for(int i=(j);i>=(k);--i)int read() { int a=0, f=1; char c=getchar(); while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); } while(isdigit(c)) a=a*10+c-'0', c=getchar(); return a*f;}int v[5000];int calc(int n) { int res = 0; while(n) { res += (n % 10) * (n % 10); n = n / 10; } return res;}signed main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int n; cin >> n; while(n != 1 && !v[n]) { v[n] = 1; n = calc(n); } if(n == 1) cout << "Yes" << endl; else cout << "No" << endl; return 0;}C
先把平方数筛出来,然后平方枚举一遍,记录次数就行了。
注意实现的方法,不要超过 。
#include<bits/stdc++.h>using namespace std;typedef long long ll;typedef unsigned long long ull;typedef pair<int,int> PII;#define MP make_pair#define fi first#define se second#define pb push_back#define eb emplace_back#define SET(a,b) memset(a,b,sizeof(a))#define CPY(a,b) memcpy(a,b,sizeof(b))#define rep(i,j,k) for(int i=(j);i<=(k);++i)#define per(i,j,k) for(int i=(j);i>=(k);--i)int read() { int a=0, f=1; char c=getchar(); while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); } while(isdigit(c)) a=a*10+c-'0', c=getchar(); return a*f;}const int N = 1e7 + 5;int n, m;vector<int> p;int v[N];signed main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin >> n; for(int i = 1;i * i < n;i++) p.pb(i * i); m = p.size(); int ans = 0; for(int i = 0;i < m;i++) { for(int j = i + 1;j < m;j++) { if(p[i] + p[j] > n) break; if(!v[p[i] + p[j]]) { ans++; v[p[i] + p[j]] = 1; } else if(v[p[i] + p[j]] == 1) { ans--; v[p[i] + p[j]] = -1; } } } cout << ans << endl; for(int x = 1;x <= n;x++) if(v[x] == 1) cout << x << " "; cout << endl; return 0;}D
这个很简单,分两种情况枚举 ,用std::unordered_map维护一下就好了。
#include<bits/stdc++.h>using namespace std;typedef long long ll;typedef unsigned long long ull;typedef pair<int,int> PII;#define MP make_pair#define fi first#define se second#define pb push_back#define eb emplace_back#define SET(a,b) memset(a,b,sizeof(a))#define CPY(a,b) memcpy(a,b,sizeof(b))#define rep(i,j,k) for(int i=(j);i<=(k);++i)#define per(i,j,k) for(int i=(j);i>=(k);--i)int read() { int a=0, f=1; char c=getchar(); while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); } while(isdigit(c)) a=a*10+c-'0', c=getchar(); return a*f;}const int N = 3e5 + 5;int n, a[N];unordered_map<int, int> p, q;signed main() { ios::sync_with_stdio(0); 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++) { ++p[a[i]], ++q[a[i]]; } ll ans = 0; for(int j = 1;j <= n - 2;--p[a[j]], j++) if(a[j] % 5 == 0) {
ans += 1ll * (p[a[j] / 5 * 3]) * (p[a[j] / 5 * 7] ); } for(int j = n;j >= 3;--q[a[j]], j--) if(a[j] % 5 == 0) { ans += 1ll * (q[a[j] / 5 * 3]) * (q[a[j] / 5 * 7]); } cout << ans << endl; return 0;}E
这里只讲我的做法,没有思维难度,但比正解复杂得多。
我们按照斜率是否 ,把线段分为两类,称为 1 类和 2 类线段。
手玩一下不难发现以下结论:
- 两个 1 类线段 可以同时选择,当且仅当 与 没有包含关系。
- 两个 2 类线段 可以同时选择,当且仅当 与 没有包含关系。
- 1 类线段 和二类线段 可以同时选择,当且仅当 和 无交。
然后我们就转化成了线段问题。
先给所有线段按照右端点递增排个序,这样无包含和无交都只需要维护一维坐标。
设 考虑前 条线段,必须选 ,最多能选出几条线段。枚举 ,根据线段类型判断一下就能转移。
这个 DP 对吗?评判标准就是一个偏序关系:如果 与 合法,那么 与之前所有的线段都合法。
如果 无交,其它线段的右端点又小于 的,所以更不可能与 交。
如果 不包含 ,但存在一个之前选出的 被 包含,那么 一定被 包含;或者右端点大于 ,出现矛盾。如图

于是满足偏序关系,DP 成立。
然后考虑优化。
把坐标离散化了,开四棵线段树,然后把 值挂在 对应的端点上。无交就在右端点线段树上查小于左端点的,无包含就在左端点线段树上查小于左端点的。
复杂度 ,常数被正解秒杀。
注意,相同右端点的线段必须在处理完函数值后一同被插入线段树,否则可能被它们的左端点更新(而右端点重合非法)。
#include<bits/stdc++.h>using namespace std;typedef long long ll;typedef unsigned long long ull;typedef pair<int,int> PII;#define MP make_pair#define fi first#define se second#define pb push_back#define eb emplace_back#define SET(a,b) memset(a,b,sizeof(a))#define CPY(a,b) memcpy(a,b,sizeof(b))#define rep(i,j,k) for(int i=(j);i<=(k);++i)#define per(i,j,k) for(int i=(j);i>=(k);--i)int read() { int a=0, f=1; char c=getchar(); while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); } while(isdigit(c)) a=a*10+c-'0', c=getchar(); return a*f;}const int N = 2e5 + 5;int n, m, b[N << 1];int f[N];struct node { int l, r, type;} a[N];bool cmp(node& a, node& b) { if(a.r != b.r) return a.r < b.r; return a.l < b.l;}void lsh() { sort(b + 1, b + m + 1); m = unique(b + 1, b + m + 1) - (b + 1); for(int i = 1;i <= n;i++) { a[i].l = lower_bound(b + 1, b + m + 1, a[i].l) - b; a[i].r = lower_bound(b + 1, b + m + 1, a[i].r) - b; }}struct SEG { int t[(N << 1) << 2]; void pushup(int x) { t[x] = max(t[x << 1], t[x << 1 | 1]); } void build(int x = 1, int l = 1, int r = m) { if(l == r) { t[x] = 0; return; } int mid = (l + r) >> 1; build(x << 1, l, mid); build(x << 1 | 1, mid + 1, r); pushup(x); } void upd(int p, int d, int x = 1,int l = 1, int r = m) { if(l == r) { t[x] = d; return; } int mid = (l + r) >> 1; if(p <= mid) upd(p, d, x << 1, l, mid); else upd(p, d, x << 1 | 1, mid + 1, r); pushup(x); } int query(int L, int R, int x = 1, int l = 1, int r = m) { if(L > R) return -1; if(L <= l && r <= R) return t[x]; int mid = (l + r) >> 1; int res = 0; if(L <= mid) res = max(res, query(L, R, x << 1, l, mid)); if(R > mid) res = max(res, query(L, R, x << 1 | 1, mid + 1, r)); return res; }} seg[4];signed main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin >> n; for(int i = 1;i <= n;i++) { cin >> a[i].l >> a[i].r; b[++m] = a[i].l, b[++m] = a[i].r; a[i].type = 1; if(a[i].l > a[i].r) { swap(a[i].l, a[i].r); a[i].type = -1; } } sort(a + 1, a + n + 1, cmp); lsh(); int ans = 0; for(int i = 0;i < 4;i++) seg[i].build(); vector<int> v; for(int i = 1;i <= n;i++) { f[i] = 1; if(a[i].type == 1) { f[i] = max(f[i], seg[0].query(1, a[i].l - 1) + 1); f[i] = max(f[i], seg[3].query(1, a[i].l - 1) + 1); } else { f[i] = max(f[i], seg[1].query(1, a[i].l - 1) + 1); f[i] = max(f[i], seg[2].query(1, a[i].l - 1) + 1); } ans = max(ans, f[i]); v.pb(i); if(a[i].r != a[i + 1].r) { for(auto x : v) { if(a[x].type == 1) { seg[0].upd(a[x].l, f[x]); seg[1].upd(a[x].r, f[x]); } else { seg[2].upd(a[x].l, f[x]); seg[3].upd(a[x].r, f[x]); } } v.clear(); } } cout << ans << endl; return 0;}F
todo
G
…
觉得这篇文章怎么样?
点个赞,让更多人看到!

评论区