Atcoder Nomura 2020A-C题解

本文深入解析了算法竞赛中的三种典型问题解决策略,包括时间计算、字符串处理和树结构优化,提供了具体的代码实现,帮助读者理解并掌握算法设计的核心思想。

A

Solution

找出该段时间的分钟数xxxx−kx-kxk即为最终的答案。

Code

#include <bits/stdc++.h>
#define int long long
using namespace std;

int a,b,c,d,m;

signed main()
{
	cin>>a>>b>>c>>d>>m;
	cout<<(c*60+d)-(a*60+b)-m<<endl;
	
	return 0;
}

B

Solution

首先,思考一下pdpdpd的意义。它为总的答案贡献了2(一个ddd和一个pdpdpd),而dddddd也为答案贡献了222(两个ddd)。

同时,ddd自己也能为答案产生111的贡献,而ppp自己无法对答案产生任何贡献。

所以我们填ppp干嘛呢?全填ddd不就行了?
于是,我们在所有的’?'上填ddd,再输出即为最终的答案。

Code

#include <bits/stdc++.h>
#define int long long
using namespace std;

int n;

signed main()
{
	string s;
	cin>>s;
	n=s.size();
	for (int i=0;i<n;i++)
	{
		if (s[i]=='?')  s[i]='D';
	}
	cout<<s<<endl;
	
	return 0;
}

花絮: 看完题面直接往dpdpdp方面想(只有pppddd啊)

C

Solution

首先,设bib_ibi表示深度为iii的那一层中节点的数量

容易得到,b1=1,bn=anb_1=1,b_n=a_nb1=1,bn=an。注意最后一层的所有节点均为叶节点

于是,我们从两个角度开始推。

①已知b1=1b_1=1b1=1
容易发现,第iii层非叶节点的数量就是bi−aib_i-a_ibiai;由于这是一棵可爱的二叉树,并且要让答案最大;所以我们要让这bi−aib_i-a_ibiai个非叶节点的孩子的数量都是2

我知道您觉得单独考虑这东西不行,因为bnb_nbn不一定是ana_nan——于是我们考虑第二种情况。

②已知bn=Anb_n=A_nbn=An
首先,每个节点有且仅有一个父节点。所以,第iii层的节点的数量就是第i+1(i<n)i+1(i<n)i+1(in)的节点的数量**加上第iii层的叶节点的数量。直接递推。

我知道您很奇怪——b1b_1b1不一定是1啊~于是,我们决定结合①②考虑答案


现在,我们通过这两种情况,大概得出了bib_ibi的值。

容易发现,一层的节点的个数多了是不好的(这是一棵二叉树,如果每一层的节点数量都少那么这种树一定存在);所以,bib_ibi通过上述两种情况计算出答案分别为x,yx,yx,y时,bi=min(x,y)b_i=min(x,y)bi=min(x,y)

注意,当ai>xia_i>x_iai>xi时(不可能在这一层产生这么多的叶节点),应该直接输出−1-11

于是答案就是Σi=1nbiΣ_{i=1}^n b_iΣi=1nbi。时间复杂度O(n)O(n)O(n)


什么?要用高精度?

本蒟蒻解释一下为什么不用高精度。首先,对于任何一棵树,从上到下,每一层节点的数量一定是单调不减的。第nnn层的节点的数量(bn)(b_n)(bn)一定是每层节点个数中的最大值,所以答案一定小于bn×nb_n×nbn×n,即101310^{13}1013。既然最大值就这么一点,那么我们用longlonglong longlonglong存储就可以了。

既然不用高精度,代码就简短啦~

Code

#include <bits/stdc++.h>
#define int unsigned long long
using namespace std;

int n,ans=0;
int a[100005],b[100005],c[100005];

int p[100005][205];

signed main()
{
	cin>>n;
	n++;
	for (int i=1;i<=n;i++)  cin>>a[i];
	
	b[1]=1,c[n]=a[n];
	for (int i=2;i<=n;i++)  b[i]=(b[i-1]-a[i-1])*2;
	for (int i=n-1;i>=1;i--)  c[i]=c[i+1]+a[i];
	for (int i=1;i<=n;i++)  ans+=min(b[i],c[i]);
	for (int i=1;i<=n;i++)
	{
		if (a[i]>b[i])  return cout<<-1<<endl,0;
	}
	cout<<ans<<endl;
	
	return 0;
}

撒花✿✿ヽ(°▽°)ノ✿撒花

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值