A题

知识点:枚举

题意:现在有\(N\)场比赛,第\(i\)场比赛允许年龄为\(A_i\)或者更小的马参赛,在这\(N\)场比赛中,问一匹\(K\)岁的马可以参加多少场比赛。

解题:直接枚举每一场比赛,比较\(A_i\)与\(K\)的大小即可,答案\(ans+=K\leq a[i]? 1:0\)。


B题

知识点:模拟

题意:现在有\(N\)个空盒子,要放入\(Q\)个球,放球按照序列\(X=(X_1,X_2,\dots,X_Q)\)把球放入盒中。具体来说,对于第\(i\)个球,会执行以下操作:

  • 如果\(X_i\geq 1\):把这个球放入编号为\(X_i\)的盒子。
  • 如果\(X_i=0\):把这个球放入当前球数量最少的盒子,若有多个这样的盒子,选择编号最小的那个。

要找出每个球放入了那个盒子。

约束条件

  • 所有输入值都是整数。

  • \(1 \leq N \leq 100\)

  • \(1 \leq Q \leq 100\)

  • \(0 \leq X_i \leq N\)

解题:开一个\(ans[n]\)记录每个球放入的位置,每次按照题意模拟即可,因为\(N,Q\)均小于等于100,时间复杂度为\(O(NQ)\)是可以过的。

int get(vector<int> cnt,int n){
int res=1,mn=inf;
for(int i=1;i<=n;i++){
if(cnt[i]<mn){
res=i;
mn=cnt[i];
}
}
return res;
}
void solve(){
int n,q;cin >> n >> q;
vector<int> a(q+1);
for(int i=1;i<=q;i++) cin >> a[i];
vector<int> ans(q+1,0),cnt(n+1,0);
for(int i=1;i<=q;i++){
if(a[i]!=0){
cnt[a[i]]++;
ans[i]=a[i];
}else{
int id_min=get(cnt,n);
cnt[id_min]++;
ans[i]=id_min;
}
}
for(int i=1;i<=q;i++){
cout << ans[i] << " ";
}
cout <<endl;
}

C题

知识点:模拟,思维

问题描述

有一个长度为 \(N\) 的整数序列 \(A\),初始时 \(A_i = i\)。需要处理总共 \(Q\) 个以下类型的查询:

  • 类型 1:将 \(A_p\) 的值修改为 \(x\)。
  • 类型 2:输出 \(A_p\) 的值。
  • 类型 3:重复执行 “将 \(A\) 的第一个元素移动到末尾” 操作 \(k\) 次。形式化地说,就是把 \(A\) 替换为 \((A_2, A_3, \ldots, A_N, A_1)\),重复执行 \(k\) 次。

约束条件

  • 所有输入值均为整数。
  • \(1 \leq N \leq 10^6\)
  • \(1 \leq Q \leq 3 \times 10^5\)
  • 所有查询满足以下约束:
    • \(1 \leq p \leq N\)
    • \(1 \leq x \leq 10^6\)
    • \(1 \leq k \leq 10^9\)

解题:我们可以拿一个变量tot记录循环左移的次数,同时对\(N\)取模。之后每次查询位置\(p\)时,查询的是将数组移动后的位置\(p\),由于我们并不移动数组,那么需要求出移动前的位置\(p_1\),有\(p_1=(p+tot) \mod N\),所以是查询\(p_1\)位置。因为在模\(N\)下,减法有逆运算,因此是可以通过记录左移次数,通过逆运算得到原来位置,询问位置\(p\)是左移之后的位置,那么对应的原来位置只需要将\(p\)向右移\(tot\)。即\(p_1\)和\(p\)是一一映射的。注意如果算出来的原来下标为0,需要特判变为n。时间复杂度为\(O(N)\)。

void solve(){
int n,q;cin >> n >> q;
vector<int> a(n+1);
for(int i=1;i<=n;i++) a[i]=i;
int sum=0;
while(q--){
int op,p,k,x;
cin >> op;
if(op==1){
cin >> p >> x;
int id=(p+sum)%n;
if(id==0) id=n;
a[id]=x;
}else if(op==2){
cin >> p;
int id=(p+sum)%n;
if(id==0) id=n;
cout << a[id] << endl;
}else{
cin >> k;
sum=(sum+k)%n;
}
}
}

D题

知识点:最短路,异或

问题陈述

存在一个有 \(N\) 个顶点和 \(M\) 条边的有向图,顶点编号从 \(1\) 到 \(N\),边编号从 \(1\) 到 \(M\)。第 \(i\) 条边是从顶点 \(A_i\) 指向顶点 \(B_i\)、权重为 \(W_i\) 的有向边。

请找出从顶点 \(1\) 到顶点 \(N\) 的一条路径(walk)中,所包含边的权重的按位异或(XOR)的最小值。

约束条件

  • \(2 \leq N \leq 1000\)
  • \(0 \leq M \leq 1000\)
  • \(1 \leq A_i, B_i \leq N\)
  • \(0 \leq W_i < 2^{10}\)
  • 所有输入值均为整数

解题:由于到顶点\(N\)的每一条路径都可能成为答案,所以需要记录从1到每个顶点的异或值都要记录,同时值域为\(2^{10}\),即每个点都要维护一个set记录从1到达这个点的异或值。之后跑spfa求出到每个点的所有异或值,只要没出现过,就要加入队列中。时间复杂度为\(O(N\times 2^{10})\leq 1e6\),是可行的。

vector<pair<int,int>> g[maxn];
int dp[maxn];//dp[i]表示从顶点1到顶点i的最小路径异或值
set<int> re[maxn];//re记录从1到每个点的所有异或值
int n,m,vis[maxn];
void spfa(int s){
re[s].insert(0);
queue<int> q;
q.push(s);
vis[s]=1;
while(q.size()){
int u=q.front();
q.pop();
vis[u]=0;
for(auto[v,w]:g[u]){
for(int ww:re[u]){
int nw=ww^w;
if(!re[v].count(nw)){
re[v].insert(nw);
if(!vis[v]){
q.push(v);
vis[v]=1;
}
}
}
}
}
}
void solve(){
cin >> n >> m;
for(int i=1;i<=m;i++){
int u,v,w;cin >> u >> v >> w;
g[u].push_back({v,w});
}
//跑spfa算法,从1出发去更新每一个顶点
spfa(1);
int ans=inf;
for(int i:re[n]){
ans=min(i,ans);
}
if(ans==inf) cout << -1 << endl;
else cout << ans << endl;
}

E题

知识点:多限制dp,状态压缩,决策树剪枝

问题陈述

高桥即将玩一个游戏,他要按顺序与 \(N\) 只怪物战斗。初始时,高桥的生命值是 \(H\),魔法值是 \(M\)。

对于第 \(i\) 只怪物,他可以选择以下行动之一:

  • 不用魔法战斗:只有当他的生命值至少为 \(A_i\) 时才能选择。选择后,他的生命值会减少 \(A_i\),且该怪物被击败。
  • 用魔法战斗:只有当他的魔法值至少为 \(B_i\) 时才能选择。选择后,他的魔法值会减少 \(B_i\),且该怪物被击败。

当所有 \(N\) 只怪物都被击败,或者他无法进行任何行动时,游戏结束。在游戏结束前,他最多能击败多少只怪物?

约束条件

  • \(1 \leq N \leq 3000\)
  • \(1 \leq H, M \leq 3000\)
  • \(1 \leq A_i, B_i \leq 3000\)
  • 所有输入值均为整数

解题:

定义\(dp[i][h][m]\)表示当前生命剩余值为\(h\),魔力剩余值为\(m\),打败前\(i\)只怪物是否可行。

初始化\(dp[0][H][M]=1\),其他全为0

状态转移:对于第\(i\)关:

\[dp[i][h][m]\oplus=dp[i-1][h+A[i]][m],(h+A[i]\leq H) \\ dp[i][h][m]\oplus=dp[i-1][h][m+B[i]],(m+B[i]\leq M)
\]

统计答案,从后往前枚举\(i\),再枚举\(h\)和\(m\),遇到可行状态那么输出这个\(i\)。时间复杂度为\(O(NMH)\),状态数达到了1e9,会TLEMLE。所以这样是错误的。考虑如何优化?状态空间一共有1e9个,即(i,h,m),我们可以转化思路,对于到达某一个关卡\(x\),如果剩余\(m\)相同,那么我们只会要\(h\)最大的那个,因为更小的\(h\)一定不会更优,所以考虑固定\(m\),定义\(dp[i][m]\)表示剩余魔力值为\(m\),打败前\(i\)个怪兽剩余的最大生命值。初始化\(dp[0][M]=H\),其他全部为-1

状态转移:对于第\(i\)关:

\[dp[i][m]= \max(dp[i][m],dp[i-1][m+B[i]]),(m+B[i] \leq M \&\& dp[i-1][m+B[i]] \neq -1 ) \\ dp[i][m]=\max(dp[i][m],dp[i-1][m]-A[i]),(dp[i-1][m] \neq {-1} \&\& dp[i-1][m]\geq A[i])
\]

之后依然从后往前枚举\(i\),枚举\(m\),判断\(dp[i][m]\geq 0\),那么输出\(i\)。时间复杂度为\(O(NM)\),1e6是可以过的。

void solve(){
int n,H,M;cin >> n >> H >> M;
vector<int> A(n+1),B(n+1);
for(int i=1;i<=n;i++){
cin >> A[i] >> B[i];
}
//dp[i][m]表示击败前i只怪物,剩余魔力值m下能够保留的最大生命值
vector<vector<int>> dp(n+1,vector<int>(M+1,-1));//-1表示状态不可达
dp[0][M]=H;
for(int i=1;i<=n;i++){
for(int m=0;m<=M;m++){
//当前怪物普攻
if(dp[i-1][m]!=-1&&dp[i-1][m]>=A[i]){
dp[i][m]=max(dp[i][m],dp[i-1][m]-A[i]);
} //当前怪物使用魔法
if(m+B[i]<=M&&dp[i-1][m+B[i]]!=-1){
dp[i][m]=max(dp[i][m],dp[i-1][m+B[i]]);
}
}
}
int ans=0;
for(int i=n;i>=0;i--){
for(int m=0;m<=M;m++){
if(dp[i][m]>=0){
ans=i;
i=-1;
break;
}
}
}
cout << ans << endl;
}

E题是真可以,这种多限制的dp可以转化为检查其中几个限制下某个限制的最值来判断是否可行,进行状态压缩。

AtCoder Beginner Contest 410的更多相关文章

  1. AtCoder Beginner Contest 100 2018/06/16

    A - Happy Birthday! Time limit : 2sec / Memory limit : 1000MB Score: 100 points Problem Statement E8 ...

  2. AtCoder Beginner Contest 052

    没看到Beginner,然后就做啊做,发现A,B太简单了...然后想想做完算了..没想到C卡了一下,然后还是做出来了.D的话瞎想了一下,然后感觉也没问题.假装all kill.2333 AtCoder ...

  3. AtCoder Beginner Contest 053 ABCD题

    A - ABC/ARC Time limit : 2sec / Memory limit : 256MB Score : 100 points Problem Statement Smeke has ...

  4. AtCoder Beginner Contest 136

    AtCoder Beginner Contest 136 题目链接 A - +-x 直接取\(max\)即可. Code #include <bits/stdc++.h> using na ...

  5. AtCoder Beginner Contest 137 F

    AtCoder Beginner Contest 137 F 数论鬼题(虽然不算特别数论) 希望你在浏览这篇题解前已经知道了费马小定理 利用用费马小定理构造函数\(g(x)=(x-i)^{P-1}\) ...

  6. AtCoder Beginner Contest 076

    A - Rating Goal Time limit : 2sec / Memory limit : 256MB Score : 100 points Problem Statement Takaha ...

  7. AtCoder Beginner Contest 079 D - Wall【Warshall Floyd algorithm】

    AtCoder Beginner Contest 079 D - Wall Warshall Floyd 最短路....先枚举 k #include<iostream> #include& ...

  8. AtCoder Beginner Contest 064 D - Insertion

    AtCoder Beginner Contest 064 D - Insertion Problem Statement You are given a string S of length N co ...

  9. AtCoder Beginner Contest 075 D - Axis-Parallel Rectangle【暴力】

    AtCoder Beginner Contest 075 D - Axis-Parallel Rectangle 我要崩溃,当时还以为是需要什么离散化的,原来是暴力,特么五层循环....我自己写怎么都 ...

  10. AtCoder Beginner Contest 075 C bridge【图论求桥】

    AtCoder Beginner Contest 075 C bridge 桥就是指图中这样的边,删除它以后整个图不连通.本题就是求桥个数的裸题. dfn[u]指在dfs中搜索到u节点的次序值,low ...

随机推荐

  1. vue cli选择lint模式

    选择代码检测和格式化方案 选择Linter / Formatter配置: 选项: ESLint with error prevention only // 仅错误预防 ESLint + Airbnb ...

  2. Skill Discovery | DoDont:使用 do + don't 示例视频,引导 agent 学习人类期望的 skill

    论文标题:Do's and Don'ts: Learning Desirable Skills with Instruction Videos NeurIPS 2024 poster. arxiv:h ...

  3. java 代理类

    简介 理解不透彻 简而言之,就是在程序运行过程中创建的类 一个代理类只有一个实例域--调用处理器.invoke? 总而言之 reflect 的理解都不是特别透彻 code package cn; im ...

  4. API生命周期管理平台,构建统一API管理门户

    API生命周期管理平台是企业在实施API战略过程中首选的IT支撑系统,通过RestCloud API生命周期管理平台可以全面管控企业的API资产.在数字化与智慧化的大趋势之下,中国经济正在经历从消费互 ...

  5. ETL数据集成丨PostgreSQL数据迁移至Hive数据库

    PostgreSQL数据迁移至Hive数据库 在现代企业数据架构中,将数据从关系型数据库如PostgreSQL迁移到分布式数据仓库系统如Hive,是一项至关重要的任务,旨在实现数据的高效存储.处理与分 ...

  6. iPaaS 平台的发展方向

    在当今数字化转型加速的时代,企业面临着前所未有的数据量增长.系统多样化及业务流程复杂化的挑战.为了应对这些挑战,企业需要一个强大的中间层来整合异构系统.优化流程并促进数据流动,而集成平台即服务(Int ...

  7. SciTech-BigDataAIML-LangChain 完整指南:使用大语言模型构建强大的应用程序 + Cursor AI Editor(用AI驱动的IDE与代码编辑器) + ComfyUI(视频音频领域的AI Workflow LLM) + Cursor

    可以先在github上研究一下: livetalking, 数字人的直播系统: metahuman-stream 已经有的成功案例:https://www.bilibili.com/video/BV1 ...

  8. Rust:axum学习笔记(4) 上传文件

    接上一篇继续,上传文件是 web开发中的常用功能,本文将演示axum如何实现图片上传(注:其它类型的文件原理相同),一般来说要考虑以下几个因素: 1. 文件上传的大小限制 2. 文件上传的类型限制(仅 ...

  9. CF1530G 题解

    考虑对操作进行转换.假设 \(a_i\) 为第 \(i\) 个 \(1\) 前面的 \(0\) 的个数. 则操作可以进行如下转换: 转换 1:选择一个长度为 \(k + 1\) 的子区间 \(a_{l ...

  10. 一步一步学习使用LiveBindings(4) 使用LiveBindings同步多个控件的数据

    一步一步学习使用LiveBindings(4) 使用LiveBindings同步多个控件的数据 假定有一个TStringGrid控件和一个TListBox控件,想要同步两个控件的数据显示,比如在TSt ...