七海ノ心象素描

所有的为时已晚都是恰逢其时

Nanami^2 avatar

Author

Nanami^2

大一学生 | 不是很聪明的样子

Telegram

我的频道

不定期推送灵感笔记

t.me/kisanami_blog
联系方式
QQ 群
1072614878
发送邮件

AtCoder Beginner Contest 439

个人题解

Nanami^2
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

先把平方数筛出来,然后平方枚举一遍,记录次数就行了。

注意实现的方法,不要超过 O(n)O(n)

#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

这个很简单,分两种情况枚举 jj,用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

这里只讲我的做法,没有思维难度,但比正解复杂得多。

我们按照斜率是否 0\ge 0,把线段分为两类,称为 1 类和 2 类线段。

手玩一下不难发现以下结论:

  1. 两个 1 类线段 i,ji, j 可以同时选择,当且仅当 [Ai,Bi][A_i, B_i][Aj,Bj][A_j, B_j] 没有包含关系。
  2. 两个 2 类线段 i,ji, j 可以同时选择,当且仅当 [Bi,Ai][B_i, A_i][Bj,Aj][B_j, A_j] 没有包含关系。
  3. 1 类线段 ii 和二类线段 jj 可以同时选择,当且仅当 [Ai,Bi][A_i, B_i][Bj,Aj][B_j, A_j] 无交。

然后我们就转化成了线段问题。

先给所有线段按照右端点递增排个序,这样无包含和无交都只需要维护一维坐标。

fif_i 考虑前 ii 条线段,必须选 ii,最多能选出几条线段。枚举 jj,根据线段类型判断一下就能转移。

这个 DP 对吗?评判标准就是一个偏序关系:如果 iijj 合法,那么 ii 与之前所有的线段都合法。

如果 i,ji, j 无交,其它线段的右端点又小于 jj 的,所以更不可能与 ii 交。

如果 ii 不包含 jj,但存在一个之前选出的 kkii 包含,那么 kk 一定被 jj 包含;或者右端点大于 jj,出现矛盾。如图

于是满足偏序关系,DP 成立。

然后考虑优化。

把坐标离散化了,开四棵线段树,然后把 fif_i 值挂在 Ai,BiA_i, B_i 对应的端点上。无交就在右端点线段树上查小于左端点的,无包含就在左端点线段树上查小于左端点的。

复杂度 O(nlogn)O(n \log n),常数被正解秒杀。

注意,相同右端点的线段必须在处理完函数值后一同被插入线段树,否则可能被它们的左端点更新(而右端点重合非法)。

#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

觉得这篇文章怎么样?

点个赞,让更多人看到!

分享这篇文章

知识因分享而增值

分类

比赛
atcoder

标签

DP
线段树
区间问题

版权声明:本文作者为 Nanami^2,首发于nanami7.top

遵循 CC BY-NC-SA 4.0 许可协议。转载请注明出处!

评论区

本评论区由 EveSunMaple 自主开发