试题A:求余数
问题描述
求12345678901234567890123456789012345678901234567890除以2023的余数。
答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
小提示:比赛时可以用python处理高精度问题
本题python代码:
a=12345678901234567890123456789012345678901234567890print(a%2023)
1e10是double类型,模运算时需要强转int
思路:
- 利用模运算的性质和幂的分配律,把大数表示成 1234567890×1010+12345678901234567890×1010+1234567890 的形式。
- 通过循环利用模运算性质计算余数,避免大数直接运算。
#include<iostream>
using namespace std;
#define int long long
signed main()
{
//12345678901234567890123456789012345678901234567890
//2345678901234567890等价于 1234567890*10^10+1234567890 的思想
int a=1234567890;
int n=5;
int ans=0;
int mod=2023;
int N=1e10;
for(int i=1;i<=n;i++)
{
ans=(ans*N%mod+a%mod)%mod;
}
cout<<ans;
return 0;
}
试题B:数位和
问题描述
只能被1和本身整除的数称为质数。
请问在1(含)到1000000(含)中,有多少个质数的各个数位上的数字之和为23。提示:599就是这样一个质数,各个数位上的数字之和为5+9+9= 23。
笞案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
思路:
- 枚举1到1000000内的所有数,对每个数判断是否为质数(只能被1和自身整除)。
- 同时计算每个质数的数位和,判断是否为23,符合条件则计数。
#include<iostream>
#include<cmath>
using namespace std;
bool isprime(int n)
{
if(n<2)return false;
for(int i=2;i<=sqrt(n);i++)
{
if(n%i==0)
return false;
}
return true;
}
bool check(int x)
{
int sum=0;
while(x)
{
sum+=x%10;
x/=10;
}
return sum==23;
}
int main()
{
int ans=0;
for(int i=2;i<=int(1e6);i++)
{
if(isprime(i)&&check(i))
{
ans++;
}
}
cout<<ans;
return 0;
}
试题C:最少步数
问题描述
小蓝要上一个楼梯,楼梯共有n级台阶(即小蓝总共要走n级)。小蓝每一步可以走1级、2级或3级台阶。
请问小蓝至少要多少步才能上到楼梯顶端?
输入格式
输入一行包含—个整数n。
输出格式
输出一行包含一个整数,表示答案。
思路:
- 根据步数(1, 2, 3步)进行简单的数学分析。
- 总步数等于台阶数除以3的商,余数决定最后是否需要多走1步或2步。
#include <iostream>
using namespace std;
const int N=1e4+10;
int a[N];
int main()
{
int x;
cin>>x;
int cnt=0;
int t=x%3;
cnt=x/3;
if(t==2||t==1)
cnt++;
cout<<cnt;
return 0;
}
试题D:转换次数
问题描述
给定一个整数,对这个整数的一次转换是指将这个整数变为这个整数的所有数位上的非零数字的乘积。
例如,对123456789进行一次转换变为1×2×3×4×5x6×7×8 ×9= 362880,再进行一次转换变为3×6×2×8×8= 2304,再进行一次转换变为2×3×4=24,再进行一次转换变为8。给定一个整数,请依次将转换过程中经历的每个整数输出,直到小于10。
输入格式
输入一行包含一个整数n。
输出格式
输出多行,每行包含一个整数。
思路:
- 对给定的数不断执行数位非零数字乘积转换,直至结果小于10。
- 在循环中计算每次转换的乘积,直至完成。
#include <iostream>
using namespace std;
#define int long long
signed main()
{
int x;
cin>>x;
if(n<10)
{
cout<<n<<endl;
return 0;
}
while(x>=10)
{
int temp=1;
while(x)
{
if(x%10!=0)
temp*=x%10;
x/=10;
}
x=temp;
cout<<temp;
}
return 0;
}
试题E:最大极小值与最小极大值
问题描述
对于一个序列a[1], a[2].. . . , a[n],如果ai]满足a[i]<ali-1]且a[i]<ai+1],则称a[i]是一个极小值,如果a[i]满足a[i]> ai-1]且a[i]> ai+1],则称a[i]是一个极大值。给定一个序列,请找到极小值中最大的和极大值中最小的。
输入格式
输入的第一行包含一个整数n,表示序列的长度。第二行包含n个整数,相邻的整数之间使用一个空格分隔,表示给定的序列。
输出格式
输出一行包含两个整数,用一个空格分隔,分别表示极小值中最大的和极大值中最小的。输入保证至少存在一个极小值,至少存在一个极大值。
思路:
- 遍历序列,通过比较相邻的数找出所有的极小值和极大值。
- 记录并更新遇到的极小值中的最大值和极大值中的最小值。
#include<iostream>
using namespace std;
const int N = 1e3 + 10, INF = 0x3f3f3f3f;
int a[N];
int main() {
int n; cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
int mi = INF, mx = -INF;
for (int i = 2; i < n; i++) {
if (a[i] < a[i - 1] && a[i] < a[i + 1]) mx = max(mx, a[i]);
if (a[i] > a[i - 1] && a[i] > a[i + 1]) mi = min(mi, a[i]);
}
cout << mx << " " << mi << endl;
return 0;
}
试题F:区间最大和
问题描述
给定一个序列α[1], a[2].. . . ,a[n]和一个整数k,请找出一个长度正好为k的区间,使得区间中所有数的和最大。
即要找到一个整数p,使得1≤p且p+k-1≤n,使得alp]+alp+1]+…+alp+k一1]最大。
输入格式
输入的第一行包含两个整数n , k。
第二行包含n个整数,相邻的整数之间使用一个空格分隔,表示给定的序列。
输出格式
输出一行包含一个整数,表示最大的区间和,你只需要输出和就行,不需要输出方案。
思路:
- 利用前缀和技术,计算所有长度为k的区间和。
- 遍历所有可能的区间,找出最大区间和。
#include <iostream>
#define int long long
using namespace std;
const int N=1e5+10;
int a[N],s[N];
signed main()
{
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++)
{
cin>>a[i];
s[i]=s[i-1]+a[i];//前缀和
}
int mx=0;
for(int l=1;l+k-1<=n;l++)
{
int r=l+k-1;
mx=max(mx,s[r]-s[l-1]);
}
cout<<mx<<endl;
return 0;
}
试题G:最后的元音
问题描述
输入一个仅包含小写英文字母的字符串,请问这个字符串中的最后一个元音是什么。在英文中,a,e,i, o,u共5个字母是元音字母,其它字母不是元音字母。
输入格式
输入一行包含一个字符串,仅由小写英文字符组成,字符串中至少包含一个元音字母。
输出格式
输出一行包含一个字符,表示答案。
思路:
- 最后一个首先想到倒着遍历.本题从字符串的尾部开始遍历,找到第一个元音字母即停止。
#include <iostream>
#include<string>
using namespace std;
int main()
{
string s;
cin>>s;
string t;
for(auto &c:s)
{
if(c=='a'||c=='e'||c=='i'||c=='o'||c=='u')
t=c;
}
cout<<t;
return 0;
}
#include <iostream>
#include<string>
using namespace std;
int main()
{
string s;
cin>>s;
string t="aeiou";
for(int i=s.size()-1;i>=0;i--)
{
if(t.find(s[i])!=-1)
{
cout<<s[i]<<endl;
return 0;
}
}
return 0;
}
试题H:公约移动
问题描述
小蓝站在一个n行m列的方格图中间,方格图的每一个方格上都标有一个正整数。
如果两个相邻方格(上下左右四个方向相邻)内的数的最大公约数大于1,则可以从其中一个方格移动到另-个方格,当然也可以从另一个方格移回第一个方格。
假设小蓝开始时站在第r行第c列,请问小蓝可以移动到方格图内的多少个方格?
输入格式
输入的第一行包含两个整数n,m,用一个空格分隔,表示方格图的行数和列数。
接下来n行,每行包含m 个正整数,相邻整数间用一个空格分隔,依次表示方格图中从第1行到第n行,每行从第1列到第m列中的数。
接下来一行包含两个整数r,c,用一个空格分隔,表示小蓝所在的行号和列号。
输出格式
输出一行包含—个整数,表示答案。
思路:
- 使用深度优先搜索(DFS)探索所有可以到达的方格。
- 利用最大公约数(GCD)判断是否可以从一个方格移动到另一个方格。
#include <iostream>
#include<string>
using namespace std;
const int N=1e3+10;
int g[N][N];//迷宫数组
bool vis[N][N];
int dx[]={1,-1,0,0};
int dy[]={0,0,1,-1};
int ans=1;int n,m;
int gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
void dfs(int x,int y)
{
for(int i=0;i<4;i++)
{
int px=x+dx[i],py=y+dy[i];
if(px>n||py>m||px<1||py<1)continue;
if(!vis[px][py]&&gcd(g[x][y],g[px][py])>1)
{
vis[px][py]=1;
ans++;
dfs(px,py);
}
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>g[i][j];
int sx,sy;cin>>sx>>sy;
vis[sx][sy]=1;
dfs(sx,sy);
cout<<ans;
return 0;
}
试题I:最大的Y
问题描述
对于一个字符矩阵,其中的一些字符构成字母v是指存在一个中间字符,从这个中间字符向下、向左上( 45度)、向右上( 45度)的字符都与中间的字符相同。
字母v的长度指同时向3个方向的相同字母延伸的最大距离。例如,下图中所有的1组成一个字母v,长度为3。
又如,下图中以第5行第6列为中心也构成一个字母v(由字符A构成),长度为1。再如,下图中以第4行第3列为中心也构成一个字母v(由字符0构成),长度为2。
给定一个字符矩阵,请找出能构成字母v的最大长度,如果无法构成字母v,请输出0。
输入格式
输入的第一行包含两个整数n, m,用一个空格分隔,表示字符矩阵的行数和列数。
接下来n行,每行包含m个字符,表示字符矩阵。
输出格式
输出一行包含—个整数,表示答案。
思路:
- 对每个矩阵中的点,向三个方向(下,左上,右上)探索,找到最长的相同字符链。
- 对所有点进行操作,记录最大的长度。
#include <iostream>
using namespace std;
const int N=1e3+10;
char a[N][N];
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>a[i][j];
int mx = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
int r = i, c = j, mx1 = -1, mx2 = -1, mx3 = -1;
//向左上延伸
while (r >= 1 && c >= 1 && a[r][c] == a[i][j]) r--, c--, mx1++;
r = i, c = j;
//向右上方向延伸
while (r >= 1 && c <= m && a[r][c] == a[i][j]) r--, c++, mx2++;
r = i, c = j;
//向下延伸
while (r <= n && a[r][c] == a[i][j]) r++, mx3++;
int lenY = min(mx1, min(mx2, mx3));
mx = max(mx, lenY);
}
}
cout << mx << endl;
return 0;
}
试题J:台阶方案
问题描述
小蓝要上一个楼梯,楼梯共有n级台阶(即小蓝总共要走n级)。小蓝每一步可以走α级、b级或c级台阶。
请问小蓝总共有多少种方案能正好走到楼梯顶端?
输入格式
输入的第一行包含一个整数n。
第二行包含三个整数a, b,c。
输出格式
输出一行包含一个整数,表示答案。答案可能很大,请输出答案除以1000000007后的余数。
思路:
- 动态规划,使用一个数组记录到达每个台阶的方案数。
- 对于每个台阶i,其方案数为到达i-a, i-b, 和i-c台阶方案数的和。
#include<iostream>
using namespace std;
const int N = 1e6 + 10, mod = 1e9 + 7;
int f[N];//f[i]代表走i级台阶的方案数
//1.边界
//f[a]=f[b]=f[c]=1;
//2.递推关系式
// f[i]=f[i-a]+f[i-b]+f[i-c]
int main() {
int n, a, b, c; cin >> n >> a >> b >> c;
f[a] = f[b] = f[c] = 1;
for (int i = 1; i <= n; i++) {
if (i >= a) f[i] = (f[i] % mod + f[i - a] % mod) % mod;
if (i >= b) f[i] = (f[i] % mod + f[i - b] % mod) % mod;
if (i >= c) f[i] = (f[i] % mod + f[i - c] % mod) % mod;
}
cout << f[n] << endl;
return 0;
}