Atcoder Regular Contest 177(ARC)题解(A-C)

A - Exchange

#include<bits/stdc++.h>
using namespace std;
int main() 
{
	int coin[10]={11,5,10,50,100,500};
   int a,b,c,d,e,f,n,now;
   cin>>a>>b>>c>>d>>e>>f>>n;
   int pep[10];
   int flag=0;
   for(int i=1;i<=n;i++)
   {
   		cin>>now;
   		while(now>=500&&f>0)
   		{
   			f--;
   			now-=500;
		}
		while(now>=100&&e>0)
   		{
   			e--;
   			now-=100;
		}
		while(now>=50&&d>0)
   		{
   			d--;
   			now-=50;
		}
		while(now>=10&&c>0)
   		{
   			c--;
   			now-=10;
		}
		while(now>=5&&b>0)
   		{
   			b--;
   			now-=5;
		}
		while(now>=1&&a>0)
   		{
   			a--;
   			now-=1;
		}
		if(now!=0)
		{
			flag=1;
			break;
		}
   	}
   	if(flag==1)
   		cout<<"No"<<endl;
   	else
   		cout<<"Yes"<<endl;
}

思路:按要求输入之后,用从大到小的货币依次尝试支付每项所需的金钱,若每次都可以让剩余金钱为0,则可以找零。

反思:刚看到这题,笔者以为这题不可以暴力求解,要用dp的知识,毕竟之前遇到过这样情况的题目:比如说有不成倍数关系的货币共两种,分别为5元和11元,可找货币数量分别为三个,一个,找零目标为15元。那么按优先选大货币的策略,会找一个11元,接着就会得到无法找零的结果,但如果直接找三个五元,就可以正确找零。

通过找规律(笔者也没找到数学证明的方法),发现只有当各个货币成整数倍关系时,才可以用本题直接求解的方法,否则要考虑dp等方法。

B - Puzzle of Lamps

#include<bits/stdc++.h>
using namespace std;
int pre=0,sum=0;
int n;
char str[40];
stack<char>qt;
int main() 
{
	cin>>n;
	cin>>str;
	int len=strlen(str);
	for(int i=len;i>=1;i--)
	{
		if(str[i-1]=='0')
		{
			if(pre==0)
			{

			}
			else
			{	
				pre--;
				sum+=pre;
				pre=0;	
			}
		}
		else if(str[i-1]=='1')
		{
			if(pre==0)
			{
				pre=i;
				sum+=pre;
			}
			else if(pre!=0)
			{		
				pre--;
			}
		}
	}
	cout<<sum<<endl;
	int pre=0,sum=0;
	for(int i=len;i>=1;i--)
	{
		if(str[i-1]=='0')
		{
			if(pre==0)
			{

			}
			else
			{	
				pre--;
				sum+=pre;
				pre=0;	
				for(int j=1;j<=i;j++)
				cout<<'B';
			}
		}
		else if(str[i-1]=='1')
		{
			if(pre==0)
			{
				for(int j=1;j<=i;j++)
					cout<<'A';
				pre=i;
				sum+=pre;
			}
			else if(pre!=0)
			{		
				pre--;
			}
		}
	}
}

思路:对题目样例一分析,找到了较为普世的开关灯方法,黑色表示关灯,橙色表示目标开关灯,红色表示当前开关灯:

输入:5

01100

输出:4

AAAB

第一步,一直开灯直到最右侧需要开的灯被打开为止

第二步,面对左侧亮灯区域的最右边需要关的灯,重复关灯直到需要关闭的最右侧灯也关闭为止

由此,即为AAAB,其他样例只需不断重复一二步骤直至获得目标状态为止。

代码就是在模拟这个过程(写的有点烂,为了模拟输出重复运行了一遍)

C - Routing

#include<bits/stdc++.h>
using namespace std;
char maze[510][510];
int MAX=2147483647; 
int n,ans=0;
typedef struct node{
	int x,y,val;
}node;
int cnt[510][510];
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
queue<node>qu;
void spfa(char c,int x,int y)
{
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			cnt[i][j]=MAX;
	cnt[y][x]=0;
	node pre={x,y,0};
	qu.push(pre);
	while(!qu.empty())
	{
		node pre={qu.front().x,qu.front().y,qu.front().val};
		qu.pop();
		for(int i=0;i<4;i++)
		{
			int dx=pre.x+dir[i][1];
			int dy=pre.y+dir[i][0];
			int plus=1;
			if(maze[dy][dx]==c||maze[dy][dx]=='P')
				plus=0;
			node a={dx,dy,pre.val+plus};
			if(dx>=1&&dx<=n&&dy>=1&&dy<=n&&cnt[dy][dx]>a.val)
			{
				cnt[dy][dx]=a.val;
				qu.push(a);
			}
		}
	}
}
int main()
{
	cin>>n;
	for(int y=1;y<=n;y++)
		for(int x=1;x<=n;x++)
			cin>>maze[y][x];		
	spfa('R',1,1);
	ans+=cnt[n][n];
	spfa('B',n,1);
	ans+=cnt[n][1];
	cout<<ans<<endl;
} 

思路:使用两次SPFA算法(笔者也是第一次写),分别从两个方向开始搜索(有点像广搜),把题目的迷宫(暂且这么叫吧)看成图,每个点都和四个方向联通,联通时通过所需的距离取决于颜色是否符合要求,如果需要改变颜色,就是距离等于一;反之,等于零。

然后开始搜索时,用队列存储,先将起点入队,然后每当起点四周有新节点的通过步数可以变小时,更新新节点的步数,并将新节点入队,起点节点出队,直到队列为空时即代表没有节点可以更新,所有节点都存储了已知可以到达的最小步数(除非有负环的情况),最后两次搜索的输出答案。

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$,如果存在,则无法完成任务。否则,可以用贪心的思想,每次从物品数量最多的盒子中取出一个物品,放入物品数量最少的盒子中。因为每次操作都会使得物品数量最多的盒子的物品数量减少,而物品数量最少的盒子的物品数量不变或增加,因此这种贪心策略可以保证最少需要的操作次数最小。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值