AtCoder Beginner Contest 343
右下角可以切换黑白背景。括号内的数为难度评分。
C. 343 (*220)
枚举开根后的数,再来判断回文。,所以最多枚举 个数。
int check(int x) {
tot = 0;
while (x) {
b[++tot] = x % 10;
x /= 10;
}
for (int i = 1; i <= tot; i++) {
if (b[i] != b[tot - i + 1]) return 0;
}
return 1;
}
signed main() {
cin >> n;
for (int i = 1; i * i * i <= n; i++) {
if (check(i * i * i)) res = max(res, i * i *i );
}
cout << res;
}
D. Diversity of Scores (*422)
开一个 map 存储每个数出现的次数。最初 出现了 次。再开一个全局变量 表示有多少个不同的数。
map<int, int> vis;
void del(int x) {
if (vis[x] == 1) res--;
vis[x]--;
}
void add(int x) {
if (vis[x] == 0) res++;
vis[x]++;
}
signed main() {
cin >> n >> m;
for (int i = 1; i <= m; i++) cin >> a[i] >> b[i];
vis[0] = n; res = 1;
for (int i = 1; i <= m; i++) {
del(t[a[i]]);
t[a[i]] += b[i];
add(t[a[i]]);
cout << res << endl;
}
}
F. Second Largest Query(*1370)
线段树做法。可以维护每个区间的最大,次大,最大出现次数,次大出现次数,合并的时候需要一些麻烦操作,不推荐此做法。
分块做法。这道题只求出严格第 大数。可以维护每一个块的最大值 ,次大值 。定义 表示数 再第 个块的出现次数。
对于修改操作 :暴力修改 ,再重新更新一遍 所属的块的最大,次大。复杂度 。
void push_up(int x) {
mx[x] = mi[x] = 0; // 必须要清空
for (int j = lx[x]; j <= rx[x]; j++) mx[x] = max(mx[x], a[j]);
for (int j = lx[x]; j <= rx[x]; j++) {
if (a[j] != mx[x]) mi[x] = max(mi[x], a[j]);
}
}
对于查询操作 :先利用 求出 的最大值,再用这个最大值去寻找次大值。再用次大值去找次大值出现次数。复杂度 。
注意事项:数的值域比较大,可以离散化!
const int N = 4e5 + 5, sq = 600;
// sq 为块长,因为 cnt 数组的空间为 n*n/sq,所以可以稍稍将块长调大。(不过在 atcoder 上不怕炸空间)
int n, q, a[N], b[N], tot;
int op[N], l[N], r[N], cnt[N][420];
int mx[N], mi[N], lx[N], rx[N], bel[N], idx;
int main() {
cin >> n >> q;
for (int i = 1; i <= n; i++) cin >> a[i], b[++tot] = a[i];
for (int i = 1; i <= q; i++) {
cin >> op[i] >> l[i] >> r[i];
if (op[i] == 1) b[++tot] = r[i];
}
sort(b + 1, b + tot + 1);
tot = unique(b + 1, b + tot + 1) - b - 1;
for (int i = 1; i <= n; i++) a[i] = lower_bound(b + 1, b + tot + 1, a[i]) - b;
for (int i = 1; i <= q; i++) {
if (op[i] == 1) r[i] = lower_bound(b + 1, b + tot + 1, r[i]) - b;
}
for (int i = 1; i <= n / sq; i++) lx[i] = (i - 1) * sq + 1, rx[i] = i * sq;
idx = n / sq;
if (n % sq) idx++, lx[idx] = rx[idx - 1] + 1, rx[idx] = n;
for (int i = 1; i <= idx; i++) {
for (int j = lx[i]; j <= rx[i]; j++) bel[j] = i;
}
for (int i = 1; i <= idx; i++) { // 处理好块内信息
for (int j = lx[i]; j <= rx[i]; j++) mx[i] = max(mx[i], a[j]), cnt[a[j]][i]++;
for (int j = lx[i]; j <= rx[i]; j++) {
if (a[j] != mx[i]) mi[i] = max(mi[i], a[j]);
}
}
for (int cas = 1; cas <= q; cas++) {
if (op[cas] == 1) {
cnt[a[l[cas]]][bel[l[cas]]]--;
a[l[cas]] = r[cas];
cnt[a[l[cas]]][bel[l[cas]]]++;
push_up(bel[l[cas]]);
}
else {
int t1 = bel[l[cas]], t2 = bel[r[cas]];
int maxn = 0, minn = 0, res = 0;
if (t1 == t2) { // 在同一个块,暴力扫一遍
for (int i = l[cas]; i <= r[cas]; i++) maxn = max(maxn, a[i]);
for (int i = l[cas]; i <= r[cas]; i++) {
if (maxn != a[i]) minn = max(minn, a[i]);
}
for (int i = l[cas]; i <= r[cas]; i++) {
if (minn == a[i]) res++;
}
cout << res << endl;
}
else {
for (int i = l[cas]; i <= rx[t1]; i++) maxn = max(maxn, a[i]);
for (int i = lx[t2]; i <= r[cas]; i++) maxn = max(maxn, a[i]);
for (int i = t1 + 1; i <= t2 - 1; i++) maxn = max(maxn, mx[i]); // maxn 求出最大值
for (int i = l[cas]; i <= rx[t1]; i++) {
if (a[i] != maxn) minn = max(minn, a[i]);
}
for (int i = lx[t2]; i <= r[cas]; i++) {
if (a[i] != maxn) minn = max(minn, a[i]);
}
for (int i = t1 + 1; i <= t2 - 1; i++) {
if (mx[i] != maxn) minn = max(minn, mx[i]);
else minn = max(minn, mi[i]);
} // minn 求出次大值
for (int i = l[cas]; i <= rx[t1]; i++) if (a[i] == minn) res++;
for (int i = lx[t2]; i <= r[cas]; i++) if (a[i] == minn) res++;
for (int i = t1 + 1; i <= t2 - 1; i++) res += cnt[minn][i]; // 统计出现次数
cout << res << endl;
}
}
}
}
G. Compress Strings(*2114)
第一次场切 不是数据结构的 G,激动。
找到一个最短串,这个串包含给定的 个串。首先可以发现,如果这 个串之间有相互包含的两个串,那么那个短串就可以忽略。比如样例 snuke
和 uk
,uk
可以完全忽视掉。
去掉包含的情况后,那么这 个串就是相交的情况了(相交的长度可以为 )。比如样例 snuke kensho
,其中 ke
就是相交的串。
那么最短长度就是:把 个串按照任意顺序拼接起来,去掉中间相交的部分后的最短长度。
可以状压 , 表示当前已经拼接了 的集合,最后一个串是串 的最短拼接长度。
转移:。即枚举串 ,将其拼接在串 的后面,并且去掉公共部分长度 。
先预处理 数组,不需要 KMP 和 hash,暴力处理就行,原因自己思考一下。总复杂度 。
#include <bits/stdc++.h>
using namespace std;
const int N = 21, M = 2e5 + 5;
int n, dp[1 << N][N], vis[N], cost[N][N], vv[N];
string s[N], t[N];
char a[N][M];
int n2, id[N], dd[N];
int get(int x, int y) {
int lenx = strlen(a[x] + 1), leny = strlen(a[y] + 1);
for (int i = leny; i >= 1; i--) {
int flg = 0;
for (int j = 1; j <= i; j++) {
if (lenx - i + j < 0) {
flg = 1;
break;
}
if (a[y][j] != a[x][lenx - i + j]) {
flg = 1;
break;
}
}
if (!flg) return i;
}
return 0;
}
int check(int x) {
for (int i = 0; i < n; i++) {
if (x >> i & 1) if (!vis[i]) return 0;
}
return 1;
}
bool cmp(int x, int y) {
return (int)s[x].size() < (int)s[y].size();
}
signed main() {
cin >> n;
for (int i = 0; i < n; i++) cin >> (a[i] + 1);
for (int i = 0; i < n; i++) {
int lena = strlen(a[i] + 1);
for (int j = 1; j <= lena; j++) s[i] += a[i][j];
}
for (int i = 0; i < n; i++) dd[i] = i;
sort(dd, dd + n, cmp);
for (int i = 0; i < n; i++) {
int flg = 0;
for (int j = i + 1; j < n; j++) {
if (s[dd[j]].find(s[dd[i]]) != string::npos) {
flg = 1;
break;
}
}
if (!flg) {
for (int j = 0; j < s[dd[i]].size(); j++) t[n2].push_back(s[dd[i]][j]);
id[n2] = dd[i], n2++;
}
}
for (int i = 0; i < n2; i++) {
for (int j = 0; j < n2; j++) if (id[i] != -1 && id[j] != -1 ) cost[i][j] = get(id[i], id[j]);
}
memset(dp, 0x3f, sizeof dp);
for (int i = 0; i < n2; i++) dp[1 << i][i] = t[i].size();
for (int i = 1; i < (1 << n2); i++) {
for (int j = 0; j < n2; j++) {
if (!(i >> j & 1) ) continue;
for (int k = 0; k < n2; k++) {
if ((i >> k & 1)) continue;
dp[i | (1 << k)][k] = min(dp[i | (1 << k)][k], dp[i][j] + (int)t[k].size() - cost[j][k]);
}
}
}
int res = 2e9;
for (int i = 0; i < n2; i++) res = min(res, dp[(1 << n2) - 1][i]);
cout << res << endl;
}
标签:
atcoder
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧