Daiwa Securities Co. Ltd. Programming Contest 2024(AtCoder Beginner Contest 383)题解
总体情况
更极限了,30分钟逆转局面,5分钟成就佳绩!
对于 lzh999
、Killer_Sans
、yxbb
:
您在 ABC383 中表现优异,获得:
永不言弃
2024年12月7日
A - Humidifier 1
题目描述
AtCoder 公司办公室有一个加湿器。当前时间是 \(0\) ,加湿器内没有水。
你要给加湿器加水 \(N\) 次。第 \(i\) 次加水( \(1 \leq i \leq N\) )发生在时间 \(T_i\) ,您加了 \(V_i\) 升水。保证所有 \(1 \leq i \leq N-1\) 的 \(T_i \le T_{i+1}\) 。
然而,加湿器漏水了,只要里面有水,单位时间内水量就会减少 \(1\) 升。
求在 \(T_N\) 时加完水后加湿器中剩余的水量。
思路分析
直接模拟即可。
代码
// Problem: A - Humidifier 1
// Contest: AtCoder - Daiwa Securities Co. Ltd. Programming Contest 2024(AtCoder Beginner Contest 383)
// URL: https://atcoder.jp/contests/abc383/tasks/abc383_a
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
//#define int long long
namespace gtx{
// Fast IO
void read(int &x){
x = 0;int h = 1;char tmp;
do{tmp=getchar();if(tmp=='-')h*=-1;}while(!isdigit(tmp));
while(isdigit(tmp)) x*=10,x+=tmp-'0',tmp=getchar();
x*=h;
}
void read(char &x){do{x=getchar();}while(x==' '||x=='\n'||x=='\r');}
void write(char x){putchar(x);}
void write(int x){
if(x<0) putchar('-'),x=-x;int st[200]={0},tot=0;
do{st[++tot]=x%10,x/=10;} while(x);
while(tot){putchar(st[tot--]+'0');}
}
void write(int x,char y){write(x);write(y);}
#ifndef int
void read(long long &x){
x = 0;int h = 1;char tmp;
do{tmp=getchar();if(tmp=='-')h*=-1;}while(!isdigit(tmp));
while(isdigit(tmp)) x*=10,x+=tmp-'0',tmp=getchar();
x*=h;
}
void write(long long x){
if(x<0) putchar('-'),x=-x;int st[200]={0},tot=0;
do{st[++tot]=x%10,x/=10;} while(x);
while(tot){putchar(st[tot--]+'0');}
}
void write(long long x,char y){write(x);write(y);}
#endif
signed main(){
int sum = 0,now = 1;
int n;cin >> n;
for(int i = 1;i<=n;i++){
int t,y;read(t);read(y);
while(now<t){
now++;sum--;
}
sum = max(sum,0);
sum += y;
}
write(sum);
return 0;
}
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
// ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int T = 1;
// gtx::read(T);
while(T--) gtx::main();
return 0;
}
B - Humidifier 2
题目描述
AtCoder 公司办公室可以表示为由 \(H\) 行和 \(W\) 列组成的网格。让 \((i, j)\) 表示从上往下第 \(i\) 行和从左往上第 \(j\) 列的单元格。
每个单元格的状态由一个字符 \(S_{i,j}\) 表示。如果 \(S_{i,j}\) 是 #
,则该单元格包含一张桌子;如果 \(S_{i,j}\) 是 .
,则该单元格是一层楼。可以保证至少有两个楼层单元格。
您将选择两个不同的楼层单元格,并在每个单元格中放置一个加湿器。
放置加湿器后,当且仅当一个单元格 \((i,j)\) 与至少一个加湿器单元格 \((i',j')\) 的曼哈顿距离 \(D\) 在内时,该单元格才被加湿。 \((i,j)\) 和 \((i',j')\) 之间的曼哈顿距离定义为 \(|i - i'| + |j - j'|\) 。需要注意的是,任何放置了加湿器的楼层单元总是加湿的。
求加湿楼层单元的最大可能数目。
思路分析
暴力枚举两个加湿器的位置,直接模拟即可。
时间复杂度:\(O(n^6)\)
代码
// Problem: B - Humidifier 2
// Contest: AtCoder - Daiwa Securities Co. Ltd. Programming Contest 2024(AtCoder Beginner Contest 383)
// URL: https://atcoder.jp/contests/abc383/tasks/abc383_b
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
//#define int long long
namespace gtx{
// Fast IO
void read(int &x){
x = 0;int h = 1;char tmp;
do{tmp=getchar();if(tmp=='-')h*=-1;}while(!isdigit(tmp));
while(isdigit(tmp)) x*=10,x+=tmp-'0',tmp=getchar();
x*=h;
}
void read(char &x){do{x=getchar();}while(x==' '||x=='\n'||x=='\r');}
void write(char x){putchar(x);}
void write(int x){
if(x<0) putchar('-'),x=-x;int st[200]={0},tot=0;
do{st[++tot]=x%10,x/=10;} while(x);
while(tot){putchar(st[tot--]+'0');}
}
void write(int x,char y){write(x);write(y);}
#ifndef int
void read(long long &x){
x = 0;int h = 1;char tmp;
do{tmp=getchar();if(tmp=='-')h*=-1;}while(!isdigit(tmp));
while(isdigit(tmp)) x*=10,x+=tmp-'0',tmp=getchar();
x*=h;
}
void write(long long x){
if(x<0) putchar('-'),x=-x;int st[200]={0},tot=0;
do{st[++tot]=x%10,x/=10;} while(x);
while(tot){putchar(st[tot--]+'0');}
}
void write(long long x,char y){write(x);write(y);}
#endif
const int MAXN = 12;
char a[MAXN][MAXN];int n,m,d;
signed main(){
read(n);read(m);read(d);
for(int i = 1;i<=n;i++){
scanf("%s",a[i]+1);
}
int ans = 0;
for(int i = 1;i<=n;i++){
for(int j = 1;j<=m;j++){
for(int x = 1;x<=n;x++){
for(int y = 1;y<=m;y++){
if(x==i&&y==j) continue;
if(a[i][j]=='#') continue;
if(a[x][y]=='#') continue;
int cnt =0 ;
for(int u1 = 1;u1<=n;u1++){
for(int u2 = 1;u2<=m;u2++){
if(a[u1][u2]=='#') continue;
if(abs(u1-i)+abs(u2-j)<=d){
cnt++;
}else if(abs(u1-x)+abs(u2-y)<=d){
cnt++;
}
}
}
ans = max(ans,cnt);
}
}
}
}
write(ans);
return 0;
}
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
// ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int T = 1;
// gtx::read(T);
while(T--) gtx::main();
return 0;
}
C - Humidifier 3
题目描述
AtCoder 公司的办公室是由 \(H\) 行和 \(W\) 列组成的网格。让 \((i, j)\) 表示从上往下第 \(i\) 行和从左往上第 \(j\) 列的单元格。
每个单元格的状态由一个字符 \(S_{i,j}\) 表示。如果 \(S_{i,j}\) 为 "#",则该单元格为墙壁;如果 \(S_{i,j}\) 为".",则该单元格为地板;如果 \(S_{i,j}\) 为 "H",则该单元格的地板上放置了加湿器。
如果从至少一个加湿器单元格向上、向下、向左或向右移动最多 \(D\) 次而不经过墙壁,则该单元格被视为加湿单元格。需要注意的是,任何有加湿器的单元格总是加湿的。
求加湿地板单元格的数量。
思路分析
小丑题。
直接将每一个加湿器放进bfs的队列里面。
如果一个点出现过两次,那么前面出现的那一次的次数一定要多于后一次出现的次数,所以相同的不进去,直接 BFS 即可。
代码
// Problem: B - Humidifier 2
// Contest: AtCoder - Daiwa Securities Co. Ltd. Programming Contest 2024(AtCoder Beginner Contest 383)
// URL: https://atcoder.jp/contests/abc383/tasks/abc383_b
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
//#define int long long
namespace gtx{
// Fast IO
void read(int &x){
x = 0;int h = 1;char tmp;
do{tmp=getchar();if(tmp=='-')h*=-1;}while(!isdigit(tmp));
while(isdigit(tmp)) x*=10,x+=tmp-'0',tmp=getchar();
x*=h;
}
void read(char &x){do{x=getchar();}while(x==' '||x=='\n'||x=='\r');}
void write(char x){putchar(x);}
void write(int x){
if(x<0) putchar('-'),x=-x;int st[200]={0},tot=0;
do{st[++tot]=x%10,x/=10;} while(x);
while(tot){putchar(st[tot--]+'0');}
}
void write(int x,char y){write(x);write(y);}
#ifndef int
void read(long long &x){
x = 0;int h = 1;char tmp;
do{tmp=getchar();if(tmp=='-')h*=-1;}while(!isdigit(tmp));
while(isdigit(tmp)) x*=10,x+=tmp-'0',tmp=getchar();
x*=h;
}
void write(long long x){
if(x<0) putchar('-'),x=-x;int st[200]={0},tot=0;
do{st[++tot]=x%10,x/=10;} while(x);
while(tot){putchar(st[tot--]+'0');}
}
void write(long long x,char y){write(x);write(y);}
#endif
const int MAXN = 1000+20;
char a[MAXN][MAXN];int n,m,d;
int h[MAXN][MAXN],s[MAXN][MAXN];
int left[MAXN][MAXN],right[MAXN][MAXN],up[MAXN][MAXN],down[MAXN][MAXN];
int vis[MAXN][MAXN],ans;
queue<pair<pair<int,int>,int>> q;
void add(int x,int y,int s){
if(!(~s)) return;
if(x<1||x>n) return;
if(y<1||y>m) return;
if(a[x][y]=='#') return;
if(vis[x][y]) return;
vis[x][y] = 1;ans++;
// cout << x<< " " << y << endl;
q.push({{x,y},s});
}
signed main(){
read(n);read(m);read(d);
for(int i = 1;i<=n;i++){
scanf("%s",a[i]+1);
}
for(int i = 1;i<=n;i++){
for(int j = 1;j<=m;j++){
if(a[i][j]=='H') add(i,j,d);
}
}
while(!q.empty()){
auto tmp = q.front();
q.pop();
add(tmp.first.first-1,tmp.first.second,tmp.second-1);
add(tmp.first.first+1,tmp.first.second,tmp.second-1);
add(tmp.first.first,tmp.first.second-1,tmp.second-1);
add(tmp.first.first,tmp.first.second+1,tmp.second-1);
}
write(ans);
return 0;
}
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
// ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int T = 1;
// gtx::read(T);
while(T--) gtx::main();
return 0;
}
D - 9 Divisors
题目描述
求恰好有 \(9\) 个正因数的不大于 \(N\) 的正整数的个数。
思路分析
首先这个题目要读懂(要看原文才知道翻译的时候把正因数翻译成为了正整数)
考虑哪些整数有 9 个因数。
如果做过 BS 期中考试卷的话我们知道完全平方数的因数个数有奇数个。
考虑一个完全平方数 \(n=a^2\)。对于所有 \(a\) 的因数 \(i\),都会有 \(\displaystyle\frac{n}{i}\neq i\),且\(\displaystyle\frac{n}{i}\in \N^+\)。
所以 \(a\) 的因数个数为 \(5\) 个。
分为两种情况
- \(a=pq(p,q\) 是质数且\(p\neq q)\),这个时候因数有 \(1,q,q^2,p,pq,pq^2,p^2,p^2q,p^2q^2\),这种情况直接使用 埃氏筛 来解决。
- \(a=p^4,n=p^8\),这个时候因数有 \(p^0,p^1,p^2,p^3,p^4,p^5,p^6,p^7,p^8\),直接暴力枚举即可。
时间复杂度:\(O(\sqrt n\log \log \sqrt n)\)。
代码
// Problem: D - 9 Divisors
// Contest: AtCoder - Daiwa Securities Co. Ltd. Programming Contest 2024(AtCoder Beginner Contest 383)
// URL: https://atcoder.jp/contests/abc383/tasks/abc383_d
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
namespace gtx{
// Fast IO
void read(int &x){
x = 0;int h = 1;char tmp;
do{tmp=getchar();if(tmp=='-')h*=-1;}while(!isdigit(tmp));
while(isdigit(tmp)) x*=10,x+=tmp-'0',tmp=getchar();
x*=h;
}
void read(char &x){do{x=getchar();}while(x==' '||x=='\n'||x=='\r');}
void write(char x){putchar(x);}
void write(int x){
if(x<0) putchar('-'),x=-x;int st[200]={0},tot=0;
do{st[++tot]=x%10,x/=10;} while(x);
while(tot){putchar(st[tot--]+'0');}
}
void write(int x,char y){write(x);write(y);}
#ifndef int
void read(long long &x){
x = 0;int h = 1;char tmp;
do{tmp=getchar();if(tmp=='-')h*=-1;}while(!isdigit(tmp));
while(isdigit(tmp)) x*=10,x+=tmp-'0',tmp=getchar();
x*=h;
}
void write(long long x){
if(x<0) putchar('-'),x=-x;int st[200]={0},tot=0;
do{st[++tot]=x%10,x/=10;} while(x);
while(tot){putchar(st[tot--]+'0');}
}
void write(long long x,char y){write(x);write(y);}
#endif
const int MAXN = 4e6+10;
int ys[MAXN],a[MAXN],b[MAXN],P[MAXN];
signed main(){
int n;
int ans = 0;
read(n);
for(int i = 2;i<MAXN;i++){
if(!ys[i]){
for(int j = 2*i;j<MAXN;j+=i){
ys[j]++;
if(ys[j]==1) a[j] = i;
else b[j] = i;
}
}else if(ys[i]==2){
if(i!=a[i]*b[i]) continue;
if(i*i<=n) ans++;
}
}
for(int i = 2;i<MAXN;i++){
if(ys[i]) continue;
if(i*i>MAXN) break;
if(i*i*i>MAXN) break;
if(i*i*i*i>MAXN) break;
if(i*i*i*i*i*i*i*i<=n) ans++;
}
write(ans);
return 0;
}
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
// ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int T = 1;
// gtx::read(T);
while(T--) gtx::main();
return 0;
}
F - Diversity
题目描述
一家商店里有 \(N\) 种商品出售。其中 \(i\) 件产品的价格为 \(P_i\) 日元,效用值为 \(U_i\) ,颜色为 \(C_i\) 。
你将从这些 \(N\) 产品中选择一个子集购买(可能一个都不)。所选产品的总价最多为 \(X\) 日元。
您的满意度为 \(S + T \times K\) ,其中 \(S\) 是所选产品的效用总和,而 \(T\) 是所选产品中不同颜色的数量。这里, \(K\) 是一个给定的常数。
您选择的产品将使您的满意度最大化。求最大满意度。
思路分析
这题唯一的瓶颈就是 \(T\) 不好处理。那我们可以将商品按照颜色排序,然后 dp。定义状态为:\(f_{i,j,0/1}\) 代表前 \(i\) 个商品中的总价为 \(j\),其中与 \(i\) 颜色一致的商品现在选/没选的最大满意度。
状态转移方程显然。
代码
// Problem: F - Diversity
// Contest: AtCoder - Daiwa Securities Co. Ltd. Programming Contest 2024(AtCoder Beginner Contest 383)
// URL: https://atcoder.jp/contests/abc383/tasks/abc383_f
// Memory Limit: 1024 MB
// Time Limit: 2500 ms
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
namespace gtx{
// Fast IO
void read(int &x){
x = 0;int h = 1;char tmp;
do{tmp=getchar();if(tmp=='-')h*=-1;}while(!isdigit(tmp));
while(isdigit(tmp)) x*=10,x+=tmp-'0',tmp=getchar();
x*=h;
}
void read(char &x){do{x=getchar();}while(x==' '||x=='\n'||x=='\r');}
void write(char x){putchar(x);}
void write(int x){
if(x<0) putchar('-'),x=-x;int st[200]={0},tot=0;
do{st[++tot]=x%10,x/=10;} while(x);
while(tot){putchar(st[tot--]+'0');}
}
void write(int x,char y){write(x);write(y);}
#ifndef int
void read(long long &x){
x = 0;int h = 1;char tmp;
do{tmp=getchar();if(tmp=='-')h*=-1;}while(!isdigit(tmp));
while(isdigit(tmp)) x*=10,x+=tmp-'0',tmp=getchar();
x*=h;
}
void write(long long x){
if(x<0) putchar('-'),x=-x;int st[200]={0},tot=0;
do{st[++tot]=x%10,x/=10;} while(x);
while(tot){putchar(st[tot--]+'0');}
}
void write(long long x,char y){write(x);write(y);}
#endif
const int MAXN = 510;
const int MAXM = 5e4+10;
const int INF = 0x3f3f3f3f;
int f[MAXM][2],n,x,k;
struct node{
int p,u,c;
}a[MAXN];
signed main(){
read(n);read(x);read(k);
for(int i = 1;i<=n;i++){
read(a[i].p);read(a[i].u);read(a[i].c);
}
sort(a+1,a+1+n,[](node a,node b){
return a.c<b.c;
});
for(int i = 1;i<=x;i++) f[i][0] = f[i][1] = -INF;
for(int i = 1;i<=n;i++){
if(i==1||a[i].c!=a[i-1].c) for(int j = 0;j<=x;j++) f[j][0] = max(f[j][0],f[j][1]);
for(int j = x;j>=a[i].p;j--){
if(i==1||a[i].c!=a[i-1].c){
f[j][1] = max({f[j][1],f[j-a[i].p][0]+k+a[i].u,f[j-a[i].p][1]+k+a[i].u});
}else{
f[j][1] = max({f[j][1],f[j-a[i].p][1]+a[i].u,f[j-a[i].p][0]+k+a[i].u});
}
}
}
int ans = 0;
for(int i = 0;i<=x;i++) ans = max({ans,f[i][0],f[i][1]});
write(ans);
return 0;
}
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
// ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int T = 1;
// gtx::read(T);
while(T--) gtx::main();
return 0;
}