国庆模拟赛1
A-Apples
思路
仔细读题后,我们可以发现,输出可以分成2种情况,apple
加s
与apple
不加s
,所以我们可以使用if/else
来实现。
参考代码
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin>>n;
if(n==1 || n==0) cout<<"Today, I ate "<<n<<" apple.";
else cout<<"Today, I ate "<<n<<" apples.";
return 0;
}
B-火柴棒等式
思路
首先可以预处理出拼每个数字需要多少根火柴棒,如拼0需要6根,拼1需要2根等等,所以我们得到了数组c,c[i]表示拼i这个数字所需要的火柴棒数量:c[10]={6,2,5,5,4,5,6,3,7,6}
要计算有多少种可能性,我们可以枚举这三个运算数分别是几,然后再来判断组成这个等式所需要的火柴棒数量是否为n,且判断这个等式是否成立。这可以用三重for循环来实现,但是由于这个等式满足A+B=C,我们可以只枚举A和B,C自然就计算出来了,只需要两重循环。
现在存在的问题是,枚举的范围是多少呢?我们可以估计一下这个和最大为多少来确定枚举范围,这个范围很难精准计算,但我们只需要保证两重for循环不超时即可。代码中给出的范围是2000,下面是分析过程:
假设我们现在有24根火柴棒(n<=24),加号和等号用掉4根,还剩20根,那么要用这20根火柴棒拼3个数字,和就不可能有5位数。原因如下:
拼5位数最少需要10根火柴棒(11111),我们把它作为和,现在还剩10根火柴棒。要满足这个加法等式,要么用一个五位数与另一个数相加,这显然不可能,因为只剩10根火柴棒了,最多只能拼一个五位数11111,没法拼另一个数了;要么就用两个四位数相加,而拼一个四位数至少要8根火柴棒(1111),也不可能。
分析到这里,我们知道最多只需要考虑到4位数。大家可以继续按类似于上面的方法分析一下,就会发现较大的四位数也不太可能,比如一个7777就用了12根火柴棒,还剩8根怎么也拼不出和为7777的数来。到最后,我们考虑枚举到2000即可。
思考的过程虽然稍显复杂,但考虑清楚过后,这道题落实到代码并不困难。
首先我们需要预处理出拼2000以内的所有数各需要多少个火柴棒,定义数组a,a[i]中存储拼i这个数需要的火柴棒数量。用一个for循环即可处理出a数组,原理是对枚举到的数进行数位分解,并加上每一位需要的火柴棒数量,具体见代码。
处理好之后,用两个for循环枚举两个加数,那么和就是i+j。我们只需要判断这三个数所需要的火柴棒数量加起来再加4(加号和等号)是否等于n即可,若等于,ans++。
最后答案就是ans。
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,a[2001]= {6},c[10]= {6,2,5,5,4,5,6,3,7,6},ans=0; //a[2001]={6}意思是a[0]=6,其他数均为0
scanf("%d",&n);
for(int i=1; i<=2000; i++)
{
int x=i;//注意到对0进行数位分解不方便,所以a[0]已经提前处理了
while(x)//对x进行数位分解 求每个数所用的火柴棒
{
a[i]=a[i]+c[x%10];//x%10是此时x的个位,a[i]加上c[x%10]即加上这一位所需要的火柴棒数量
x=x/10;//分解下一位
}
}
for(int i=0; i<=2000; i++)
{
for(int j=0; j<=2000; j++)
if(i+j<=2000 && a[i]+a[j]+a[i+j]+4==n) ans++; //这三个数所需要的火柴棒数量相加,还有加号与等号
}
printf("%d",ans);
return 0;
}
C-守望者的逃离
思路:贪心
总的来说就是能闪则闪,闪烁在能闪时一定比跑的快。但是在最后一点时间内,跑有可能比闪更快,所以也需要计算跑步能跑多远,取一个较大值。
具体做法是一秒一秒地枚举,看当前最远能走多远。定义两个变量,s1表示在当前这一秒跑步能得到的最远距离,s2表示在当前这一秒闪烁(或等待回魔法值)能得到的最远距离。很显然,如果不是在回魔法值的话,闪烁一定是会比跑步快的,只是在部分时候闪烁走的距离会短于跑步的距离。
每当s2>s1时,我们就更新s1为s2,表示之前的时间我们均在闪烁(这样能走的更远),从下一秒开始才跑步。当s1>=s2时,不做任何操作。这样也保证了s1无论在什么时候都>=s2。每秒处理完之后,我们用s1和s进行比较,如果已经跑出去了,就输出Yes和当前时间,如果到最后都没有跑出去,就输出No。
#include <bits/stdc++.h>
using namespace std;
int main()
{
int m,s,t,now=0;
cin>>m>>s>>t;
int s1=0,s2=0;//存放跑步能走的距离和用闪烁能走的距离
for(int i=1; i<=t; i++) //一个个时间去推
{
s1+=17;//闪现和跑步分别进行
if(m>=10)
{
s2+=60; //如果有魔法值能够闪现肯定要闪现
m-=10;
}
else m+=4; //没魔法值了这一回合就用来回魔法值
if(s2>s1) s1=s2;//闪现的快了就把跑步的替换成闪现的
if(s1>s) //跑出去了就输出当前时间
{
cout<<"Yes"<<endl<<i<<endl;
return 0;
}
}
cout<<"No"<<endl<<s1<<endl;//时间都用完了还没跑出去,输出“No”和s1的值
return 0;
}
D-产生数
该题有视频讲解,这里给出代码:
#include<bits/stdc++.h>
using namespace std;
int cnt;
int c[10];
int book[10];
int rule[10][10];
char a[40];
int ans[1234567],k;
void mul(int x)//高精度乘法 ans(高精度)*=x(低精度)
{
for(int i=1;i<=ans[0];i++) ans[i]*=x;//乘法
ans[0]++;//最高位可能有进位 所以位数++
for(int i=1;i<=ans[0];i++) //进位
{
ans[i+1]+=ans[i]/10;
ans[i]=ans[i]%10;
}
while(ans[ans[0]]==0&&ans[0]>1) ans[0]--;//去除前导0
}
void dfs(int x)//当前遍历到了x这个数字
{
book[x]=1;//做标记 防止重复遍历
cnt++; //每遍历到一个新数字 cnt++
for(int i=0;i<=9;i++)
{
if(rule[x][i]&&book[i]==0) dfs(i);
}
}
int main()
{
cin>>a>>k;
for(int i=1;i<=k;i++)
{
int u,v;
scanf("%d%d",&u,&v);
rule[u][v]=1;//有一条u->v的规则
}
for(int i=0;i<=9;i++) rule[i][i]=1;//显然可以从自己变到自己 相当于没有变
for(int i=0;i<=9;i++)
{
for(int j=0;j<=9;j++) book[j]=0;//把标记数组清零
cnt=0;
dfs(i);//从i开始搜索它能够变化成的数字
c[i]=cnt;//i这个数字有cnt种变化方式
}
ans[0]=1; ans[1]=1;//做乘法要初始化ans=1
//ans[0]存储答案的长度 后面从低位到高位存储具体的数
int len=strlen(a);
for(int i=0;i<len;i++) mul(c[a[i]-'0']); //把每个数字变化方式的数量相乘 要用高精度
for(int i=ans[0];i>=1;i--) cout<<ans[i];//从高位到低位输出答案
return 0;
}