Atcoder Beginner Contest 410 A-F题解

AB

#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=x*10+c-48;
	x=(f ? -x : x);
	return;
}
int n,k;
int a[maxn];
int main(){
	int in;
	int ans=0;
	read(n);
	for(int i=1;i<=n;i++){
		read(a[i]);
	}
	read(k);
	for(int i=1;i<=n;i++){
		if(k<=a[i]) ++ans;
	}
	printf("%d",ans);
	return 0;
} 

B题注意数据范围,100的话直接暴力就可以了

#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=x*10+c-48;
	x=(f ? -x : x);
	return;
}
int a[maxn];
int n,q;
int main(){
	read(n),read(q);
	int in;
	for(int i=1;i<=q;i++){
		read(in);
		if(in==0){
			int ansi=n;
			for(int i=n-1;i>=1;i--){
				if(a[ansi]>=a[i]) ansi=i;
			}
			++a[ansi];
			printf("%d ",ansi);
		}
		else{
			++a[in];
			printf("%d ",in);
		}
	}
	return 0;
} 

C

唯一会改变序列的操作只有重复 将A的第一个元素移至末尾 的操作k次
所有只要维护一个序列开头就好了
注意k的数据范围较大,记得及时取余,嫌麻烦开long long也可以

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=x*10+c-48;
	x=(f ? -x : x);
	return;
}
int a[maxn];
int n,q;
int p=0;
int main(){
	read(n),read(q);
	for(int i=1;i<=n;i++) a[i]=i;
	int op,x;
	for(int i=1;i<=q;i++){
		read(op),read(x);
		if(op==3){
			p=(p-1+x)%n+1;
		}
		else if(op==2){
			x=(p+x-1)%n+1;
			printf("%d\n",a[x]);
		}
		else{
			int k;
			read(k);
			x=(p+x-1)%n+1;
			a[x]=k;
		}
	}
	return 0;
} 

D

数据范围较小,搜索就可以了
状态也很少,开个布尔类型的二维数组记录就好了,即i点能不能到达j的值
我也在想能不能用位运算特点做,但暂时没想到
这道题卡dfs,请用bfs解决

#include<bits/stdc++.h>
using namespace std;
const int maxn=1025;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=x*10+c-48;
	x=(f ? -x : x);
	return;
}
struct edge{
	int v;
	long long w;
};
struct bs{
	int u;
	long long w;
};
int head[maxn],nxt[maxn];
edge e[maxn];
int cnt;
void init_mp(){
	memset(head,-1,sizeof(head));
	cnt=-1;
	return;
}
void add_edge(int u,int v,int w){
	e[++cnt]=(edge){v,w};
	nxt[cnt]=head[u];
	head[u]=cnt;
	return;
}
int n,m;
int vis[maxn];
int f[maxn][maxn];
void bfs(){
	queue<edge> q;
	q.push((edge){1,0});
	while(!q.empty()){
		edge u=q.front();
		q.pop();
		for(int i=head[u.v];~i;i=nxt[i]){
			if(!f[e[i].v][e[i].w^u.w]){
				f[e[i].v][e[i].w^u.w]=1;
				q.push((edge){e[i].v,e[i].w^u.w});
			}
		}
	}
	return;
}
int main(){
	read(n),read(m);
	int u,v,w;
	init_mp();
	for(int i=1;i<=m;i++){
		read(u),read(v),read(w);
		add_edge(u,v,w); 
	}
	bfs();
	for(int i=0;i<maxn;i++){
		if(f[n][i]){
			printf("%d",i);
			return 0;
		}
	}
	printf("-1");
	return 0;
} 

E

动态规划,类似于背包问题,设计状态f[i]如下:
当生命值为i时,能够保留的最多魔力值

初始化每个f[i]m
状态转移方程如下:
if(i<a) f[i]-=b; 若生命不够,使用魔力
else f[i]=max(f[i]-b,f[i-a]); 若生命足够,选择最优解

每次只要看所有f[i]中还有没有大于或等于0的就可以判断该怪兽能不能被打败

注意点:生命和魔力值可以为0,怪兽是按照顺序打的

#include<bits/stdc++.h>
using namespace std;
const int maxn=3005;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=x*10+c-48;
	x=(f ? -x : x);
	return;
}
int f[maxn];
int n,h,m;
int main(){
	read(n),read(h),read(m);
	for(int i=0;i<=h;i++) f[i]=m;
	int a,b;
	int ans=-1;
	for(int i=1;i<=n;i++){
		read(a),read(b);
		if(ans>-1) continue;
		bool ed=0;
		for(int i=h;i>=0;i--){
			if(i<a) f[i]-=b;
			else f[i]=max(f[i]-b,f[i-a]);
			if(f[i]>=0) ed=1;
		}
		if(!ed) ans=i-1;
	}
	printf("%d",ans==-1 ? n : ans);
	return 0;
} 

F

第一道补出来的F题

涉及矩阵的题,可以联想到计算每一列的前缀和,然后枚举两个行坐标,在行内进行双指针操作,详见洛谷P8783

不过这道题显然不能用双指针,但是前一步的优化操作可以采取

先把矩阵转换为-1,1的矩阵,然后问题就变成了矩阵和为0

通过这样的方法在几行之间求前缀和,可以得出如果某两个位置的前缀和相同,那么该矩阵和为0

这里还有两点优化:

1.时间复杂度为O(n*n*m),nn,m中较小的

2.使用map会超时,这里用的是数组+偏移来用作桶,同时用队列记录发生改变的量以便归零

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+5;
void read(int& x){
	char c;
	bool f=0;
	while((c=getchar())<48) f|=(c==45);
	x=c-48;
	while((c=getchar())>47) x=x*10+c-48;
	x=(f ? -x : x);
	return;
}
void read(char& c){
	do{
		c=getchar();
	}while(c==10||c==13);
	return;
}
int q;
int n,m;
vector<vector<int> > mp;
int t[maxn<<1];
int main(){
	read(q);
	char in;
	while(q--){
		read(n),read(m);
		if(n>m){
			mp.resize(m+1);
			for(int i=0;i<=m;i++) mp[i].resize(n+1);
			for(int i=1;i<=n;i++){
				for(int j=1;j<=m;j++){
					read(in);
					if(in=='.') mp[j][i]=-1;
					else mp[j][i]=1;
				}
			}
			swap(n,m);
		}
		else{
			mp.resize(n+1);
			for(int i=0;i<=n;i++) mp[i].resize(m+1);
			for(int i=1;i<=n;i++){
				for(int j=1;j<=m;j++){
					read(in);
					if(in=='.') mp[i][j]=-1;
					else mp[i][j]=1;
				}
			}
		}
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				mp[i][j]+=mp[i-1][j];
			}
		}
		long long ans=0;
		queue<int> que;
		for(int i=1;i<=n;i++){
			for(int j=i;j<=n;j++){
				int p=0;
				t[maxn]=1;
				for(int k=1;k<=m;k++){
					p+=mp[j][k]-mp[i-1][k];
					ans+=t[p+maxn];
					if(!t[p+maxn]) que.push(p+maxn);
					++t[p+maxn];
				}
				while(!que.empty()){
					t[que.front()]=0;
					que.pop();
				}
			}
		}
		printf("%lld\n",ans);
	}
	return 0;
}

posted @ 2025-06-14 22:08  huangems  阅读(82)  评论(0)    收藏  举报