AtCoder Beginner Contest 240 C~F题解

AtCoder Beginner Contest 240

C

题意:给定序列 A , B A,B A,B,可以跳跃N次,第 i i i次跳跃可以选择 A i 或 B i A_i或B_i AiBi ,向前跳对应的步数,问是否恰好跳N次,最终在X的位置。

数据范围较小,因此可以直接dp , 不用考虑怎么优化

code:

#include<bits/stdc++.h>

using namespace std;
#define endl '\n'
#define ios std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
#define x first
#define y second

typedef pair<int,int> pii;
//head

const int N=1e4+10,mod=998244353;

int a[N],b[N];
int dp[100][N][2];
void work()
{
	int n,x;
	cin>>n>>x;
	for(int i=1;i<=n;i++){
		cin>>a[i]>>b[i];
	}
	dp[0][0][0]=1,dp[0][0][1]=1;
	for(int i=1;i<=n;i++){

		for(int j=1;j<=x;j++){
			if(j>=a[i]) dp[i][j][0]=max(dp[i-1][j-a[i]][0],dp[i-1][j-a[i]][1]);
			if(j>=b[i]) dp[i][j][1]=max(dp[i-1][j-b[i]][0],dp[i-1][j-b[i]][1]);
		}
	}
	int ans=max(dp[n][x][0],dp[n][x][1]);
	if(ans) cout<<"Yes"<<endl;
	else cout<<"No"<<endl;
	
}
signed main()
{
	int t;
	//cin>>t;
	t=1;
	while(t--) work();

	return 0;
}

D

题意:有N个球,每个球上面有数字,若上面的数字为 i i i ,则连续 i i i 个球可以消去,类似于消消乐。问在插入每个球后,还剩下几个球。

直接根据题意模拟即可,本人代码写的比较丑陋,可以有更简洁的方法模拟。

code:

#include<bits/stdc++.h>

using namespace std;
#define endl '\n'
#define ios std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
#define x first
#define y second

typedef pair<int,int> pii;
//head

const int N=2e5+10,mod=998244353;

int cnt[N];
vector<int> v[N];
void work()
{
	
	int n;
	cin>>n;
	stack<int> q;
	int s=0,num=0;
	
	for(int i=1;i<=n;i++){
		int x; cin>>x;
		num++;
		//if(i==n) cout<<v[s].size()<<"_____"<<endl;
		if(q.empty()) q.push(x),s++,v[s].push_back(x);
		else {
			if(q.top()==x) {
				v[s].push_back(x);
				if(v[s].size()==x) {
					num-=x; 
					q.pop();
					v[s].clear();
					s--;
				}
			}
			else {
				q.push(x),s++,v[s].push_back(x);
			}
		}
		//cout<<s<<"##"<<i<<endl;
		cout<<num<<endl;
	}
}
signed main()
{
	int t;
	//cin>>t;
	t=1;
	while(t--) work();

	return 0;
}

E

题意:略 。

题面看着有点吓人,但是其实很简单,分析完后其实不难看出,其实最大的数就是叶子节点的总数,因为每个叶子节点两两独立,贪心的构造的话,肯定是一个叶子节点用一个数,即 L i = R i L_i=R_i Li=Ri ,然后根据题目的限制条件,根据子节点更新父节点的信息即可。

code:

#include<bits/stdc++.h>

using namespace std;
#define endl '\n'
#define ios std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
#define x first
#define y second

typedef pair<int,int> pii;
//head

const int N=4e5+10,mod=998244353;

int e[N],ne[N],h[N],idx;
int l[N],r[N];
int id[N];
int cnt;
void add(int a,int b)
{
	e[idx]=b; ne[idx]=h[a]; h[a]=idx++;
}
void dfs(int u,int fa)
{
	bool f=0;
	for(int i=h[u];~i;i=ne[i]){
		int j=e[i];
		if(j==fa) continue;
		f=1;
		dfs(j,u);
	}
	if(!f) id[u]=++cnt;
}

void dfs1(int u,int fa){
	if(id[u]){
		l[u]=r[u]=id[u];
		return ;
	}
	l[u]=1e9,r[u]=-1e9;
	for(int i=h[u];~i;i=ne[i]){
		int j=e[i];
		if(j==fa) continue;
		dfs1(j,u);
		l[u]=min(l[u],l[j]);
		r[u]=max(r[u],r[j]);
	}
}
void work()
{
	int n;
	cin>>n;
	memset(h,-1,sizeof h);
	for(int i=1;i<=n-1;i++){
		int a,b;
		cin>>a>>b;
		add(a,b); add(b,a);
	}
	dfs(1,-1);
	dfs1(1,-1);
	for(int i=1;i<=n;i++) cout<<l[i]<<" "<<r[i]<<endl;
	
}
signed main()
{
	int t;
	//cin>>t;
	t=1;
	while(t--) work();

	return 0;
}

F

题意:给定序列 C C C x i , y i x_i,y_i xi,yi 表示 C C C 的这一段有 y i 个 x i y_i个x_i yixi , C 的总长度为 M , 1 ≤ M ≤ 1 0 9 C的总长度为M, 1\leq M \leq 10^9 C的总长度为M,1M109.

B 表示 C 的前缀和序列 B表示C的前缀和序列 B表示C的前缀和序列

A 表示 B 的前缀和序列 A表示B的前缀和序列 A表示B的前缀和序列

问序列A的最大值为多少。

题目看着有点复杂,暴力做肯定会T飞,因此要去发掘一些性质。可以发现序列B是由一段一段的折线组成的,图是从大佬那偷来的img

可以发现,当B大于0时,A肯定是一直在增加的,当B小于0时,A在慢慢减小,同时我们也比较好算出A的某一项的值,因为可以看成是等差数列的前缀和。

那么A何时可能取到最大值呢?首先判一下端点处,这是为了防止计算一些边界情况。然后由于B在0的上方A才会一直增加,那就找到B什么时候会下降到0的下方,此时A将要减少,因此此时可能会取到最大值。

因为实际上B是由一个个离散的点构成的,因此我们要找到B在下降到0的过程中,在0的上方并且最接近0的值是多少

实际写的代码判断了所有的右端点和上述的可能出现最大值的点。

code:

#include<bits/stdc++.h>

using namespace std;
#define endl '\n'
#define ios std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
#define x first
#define y second

typedef pair<int,int> pii;
//head

const int N=4e5+10,mod=998244353;

int x[N],y[N];

void work()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++) {
		cin>>x[i]>>y[i];
	}
	int ans=-1e18,sum=0;//sum为A的值
	int nb=0;//当前B的值
	for(int i=1;i<=n;i++){
		int l=nb+x[i],r=nb+x[i]*y[i];
		ans=max(ans,sum+l);

		if(x[i]<0&&l>0&&r<0){ //如果B会下降到0点以下
			int d=abs(x[i]);
			int s=l-l/d*d; //找到最接近0的那个点
			int cnt=(l-s)/d;
			ans=max(ans,sum+(l+s)*(cnt+1)/2);
		}
		sum+=(l+r)*y[i]/2;
		ans=max(ans,sum);
		nb=r;
	}
	cout<<ans<<endl;
	
}
signed main()
{
	int t;
	cin>>t;
	//t=1;
	while(t--) work();

	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AtCoder Beginner Contest 134 是一场 AtCoder 的入门级比赛,以下是每道题的简要题解: A - Dodecagon 题目描述:已知一个正十二边形的边长,求它的面积。 解题思路:正十二边形的内角为 $150^\circ$,因此可以将正十二边形拆分为 12 个等腰三角形,通过三角形面积公式计算面积即可。 B - Golden Apple 题目描述:有 $N$ 个苹果和 $D$ 个盘子,每个盘子最多可以装下 $2D+1$ 个苹果,求最少需要多少个盘子才能装下所有的苹果。 解题思路:每个盘子最多可以装下 $2D+1$ 个苹果,因此可以将苹果平均分配到每个盘子中,可以得到最少需要 $\lceil \frac{N}{2D+1} \rceil$ 个盘子。 C - Exception Handling 题目描述:给定一个长度为 $N$ 的整数序列 $a$,求除了第 $i$ 个数以外的最大值。 解题思路:可以使用两个变量 $m_1$ 和 $m_2$ 分别记录最大值和次大值。遍历整个序列,当当前数不是第 $i$ 个数时,更新最大值和次大值。因此,最后的结果应该是 $m_1$ 或 $m_2$ 中较小的一个。 D - Preparing Boxes 题目描述:有 $N$ 个盒子和 $M$ 个物品,第 $i$ 个盒子可以放入 $a_i$ 个物品,每个物品只能放在一个盒子中。现在需要将所有的物品放入盒子中,每次操作可以将一个盒子内的物品全部取出并分配到其他盒子中,求最少需要多少次操作才能完成任务。 解题思路:首先可以计算出所有盒子中物品的总数 $S$,然后判断是否存在一个盒子的物品数量大于 $\lceil \frac{S}{2} \rceil$,如果存在,则无法完成任务。否则,可以用贪心的思想,每次从物品数量最多的盒子中取出一个物品,放入物品数量最少的盒子中。因为每次操作都会使得物品数量最多的盒子的物品数量减少,而物品数量最少的盒子的物品数量不变或增加,因此这种贪心策略可以保证最少需要的操作次数最小。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值