文章目录
A 试题 算法训练 寻找数组中最大值
难度:简单 类型:基本算法-枚举
资源限制
时间限制:1.0s 内存限制:512.0MB
问题描述
对于给定整数数组a[],寻找其中最大值,并返回下标。
输入格式
整数数组a[],数组元素个数小于1等于100。输出数据分作两行:第一行只有一个数,表示数组元素个数;第二行为数组的各个元素。
输出格式
输出最大值,及其下标
样例输入
3
3 2 1
样例输出
3 0
解题思路:
直接暴力遍历比较值并记录下标即可。
代码如下。
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
int *m = new int[n];
for(int i=0;i<n; i++){
cin>>m[i];
}
int max = m[0];
int index = 0;
for(int i=1; i<n; i++){
if(max < m[i]){
max = m[i];
index = i;
}
}
cout<<max<<" "<<index;
return 0;
}
B 试题 算法提高 日期计算
难度:中等 类型:数学-计算日期
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
已知2011年11月11日是星期五,问YYYY年MM月DD日是星期几?注意考虑闰年的情况。尤其是逢百年不闰,逢400年闰的情况。
输入格式
输入只有一行
YYYY MM DD
输出格式
输出只有一行
W
数据规模和约定
1599 <= YYYY <= 2999
1 <= MM <= 12
1 <= DD <= 31,且确保测试样例中YYYY年MM月DD日是一个合理日期
1 <= W <= 7,分别代表周一到周日
样例输入
2011 11 11
样例输出
5
解题思路:
第一种暴力算应求日期距离题目标准日期的天数,然后对7取余操作得到星期数,注意所求日期距离标准日期前或后,公式如下图30点。
第二种方法直接用吉姆拉尔森公式或者蔡勒公式一步登天算出星期数。
代码如下,我是用了基姆拉尔森公式求星期数。
#include<bits/stdc++.h>
using namespace std;
int weekday1( int y, int m, int d ){ //用基姆拉尔森公式求星期数
if( m==1 || m==2 )
m+=12, y--;
int w = ( d + 2*m + 3*(m+1)/5 + y + y/4 - y/100 + y/400)%7;
return ++w; //加 1 是为了符合统一约定:用数字 1~7 代表星期一~星期天。
}
int main(){
int year, month, day;
cin>>year>>month>>day;
cout<<weekday1(year, month, day);
return 0;
}
C 试题 算法提高 上帝造题五分钟
难度:简单 类型:基本算法-枚举
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
第一分钟,上帝说:要有题。于是就有了L,Y,M,C
第二分钟,LYC说:要有向量。于是就有了长度为n写满随机整数的向量
第三分钟,YUHCH说:要有查询。于是就有了Q个查询,查询向量的一段区间内元素的最小值
第四分钟,MZC说:要有限。于是就有了数据范围
第五分钟,CS说:要有做题的。说完众神一哄而散,留你来收拾此题
输入格式
第一行两个正整数n和Q,表示向量长度和查询个数
接下来一行n个整数,依次对应向量中元素:a[0],a[1],…,a[n-1]
接下来Q行,每行两个正整数lo,hi,表示查询区间[lo, hi]中的最小值,即min(a[lo],a[lo+1],…,a[hi])。
输出格式
共Q行,依次对应每个查询的结果,即向量在对应查询区间中的最小值。
样例输入
7 4
1 -1 -4 8 1 2 -7
0 0
1 3
4 5
0 6
样例输出
1
-4
1
-7
样例说明
第一个查询[0,0]表示求min{a[0]}=min{1}=1
第二个查询[1,3]表示求min{a[1],a[2],a[3]}=min{-1,-4,8}=-4
第三个查询[4,5]表示求min{a[4],a[5]}=min{1,2}=1
第四个查询[0,6]表示查询整个向量,求min{a[0…6]}=min{1,-1,-4,8,1,2,-7}=-7
数据规模和约定
1<=n<=1984,1<=Q<=1988,向量中随机整数的绝对值不超过1,000
解题思路:
遍历各个查询区间得到最小值即可。要是问题是求区间加减的总值就可以构造一波线段树来解答。
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,Q; int l,r;
cin>>n>>Q;
int *m = new int[n];
for(int i=0; i<n; i++){
cin>>m[i];
}
while(Q--){
cin>>l>>r;
int min = m[l];
for(int i=l+1; i<=r; i++){
if(min>m[i]){
min = m[i];
}
}
cout<<min<<endl;
}
return 0;
}
D 试题 算法提高 矩阵相乘
难度:简单 类型:数学-矩阵-矩阵运算
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
小明最近在为线性代数而头疼,线性代数确实很抽象(也很无聊),可惜他的老师正在讲这矩阵乘法这一段内容。
当然,小明上课打瞌睡也没问题,但线性代数的习题可是很可怕的。
小明希望你来帮他完成这个任务。
现在给你一个ai行aj列的矩阵和一个bi行bj列的矩阵,
要你求出他们相乘的积(当然也是矩阵)。
(输入数据保证aj=bi,不需要判断)
输入格式
输入文件共有ai+bi+2行,并且输入的所有数为整数(long long范围内)。
第1行:ai 和 aj
第2~ai+2行:矩阵a的所有元素
第ai+3行:bi 和 bj
第ai+3~ai+bi+3行:矩阵b的所有元素
输出格式
输出矩阵a和矩阵b的积(矩阵c)
(ai行bj列)
样例输入
2 2
12 23
45 56
2 2
78 89
45 56
样例输出
1971 2356
6030 7141
解题思路:
了解矩阵相乘运算即可,用二维数组表示矩阵,然后模拟出矩阵乘法运算。也可背个矩阵模板,矩阵各种运算方法都有,模板式解题。
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
int a[N][N], b[N][N], c[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 p, q;
cin >> p >> q;
for (int i = 1; i <= p; i ++)
for (int j = 1; j <= q; j ++)
cin >> b[i][j];
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= q; j ++)
for (int k = 1; k <= m; k ++)
c[i][j] += a[i][k] * b[k][j];
for (int i = 1; i <= n; i ++)
{
for (int j = 1; j <= q; j ++)
cout << c[i][j] << " ";
cout << endl;
}
return 0;
}
E 试题 算法提高 递推求值
难度:难 类型:数学-矩阵-快速幂
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
已知递推公式:
F(n, 1)=F(n-1, 2) + 2F(n-3, 1) + 5,
F(n, 2)=F(n-1, 1) + 3F(n-3, 1) + 2F(n-3, 2) + 3.
初始值为:F(1, 1)=2, F(1, 2)=3, F(2, 1)=1, F(2, 2)=4, F(3, 1)=6, F(3, 2)=5。
输入n,输出F(n, 1)和F(n, 2),由于答案可能很大,你只需要输出答案除以99999999的余数。
输入格式
输入第一行包含一个整数n。
输出格式
输出两行,第一行为F(n, 1)除以99999999的余数,第二行为F(n, 2)除以99999999的余数。
样例输入
4
样例输出
14
21
数据规模和约定
1<=n<=10^18。
解题思路:
传统递归方法这道题会超时。所以我们采取矩阵快速幂的方法计算递推式,递推式可以化为矩阵乘积。
1.构造出递推矩阵
2.对构造出的矩阵B,进行B^x的快速幂,乘积换成矩阵乘法。
3.最后矩阵的第一行第一列和第二列就是a[x]和a[y]。
但是往往构造矩阵是难点,转载一个别人博客写的矩阵构造方法:https://www.cnblogs.com/asdfknjhu/p/13339239.html
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=99999999;
struct matrix
{
ll a[8][8];
};
matrix multiply(matrix x,matrix y,int m,int n,int s)
{
matrix tmp;
memset(tmp.a,0,sizeof(tmp.a));
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
for(int k=0;k<s;k++){
tmp.a[i][j]=(tmp.a[i][j] + (x.a[i][k] * y.a[k][j])%mod)%mod;
}
}
}
return tmp;
}
matrix tmp={
0,1,1,0,0,0,0,0,
1,0,0,1,0,0,0,0,
0,0,0,0,1,0,0,0,
0,0,0,0,0,1,0,0,
2,3,0,0,0,0,0,0,
0,2,0,0,0,0,0,0,
1,0,0,0,0,0,1,0,
0,1,0,0,0,0,0,1
};
int main()
{
matrix res;
ll f[8]={6,5,1,4,2,3,5,3};
ll sum1,sum2,n;
memset(res.a,0,sizeof(res.a));
for(int i=0;i<8;i++){
res.a[i][i]=1;
}
cin>>n;
if(n==1)
cout<<"2"<<endl<<"3"<<endl;
if(n==2)
cout<<"1"<<endl<<"4"<<endl;
if(n==3)
cout<<"6"<<endl<<"5"<<endl;
if(n>=4){
n-=3;
while(n) //矩阵快速幂
{
if(n&1) res=multiply(res,tmp,8,8,8);
n>>=1;
tmp=multiply(tmp,tmp,8,8,8);
}
sum1=0;
sum2=0;
for(int i=0;i<8;i++)
{
sum1=(sum1+(f[i]*res.a[i][0])%mod)%mod;
sum2=(sum2+(f[i]*res.a[i][1])%mod)%mod;
}
cout<<sum1<<endl;
cout<<sum2<<endl;
}
return 0;
}
F 试题 历届试题 数字游戏
难度:中等 类型:基本算法-构造-规律
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
栋栋正在和同学们玩一个数字游戏。
游戏的规则是这样的:栋栋和同学们一共n个人围坐在一圈。栋栋首先说出数字1。接下来,坐在栋栋左手边的同学要说下一个数字2。再下面的一个同学要从上一个同学说的数字往下数两个数说出来,也就是说4。下一个同学要往下数三个数,说7。依次类推。
为了使数字不至于太大,栋栋和同学们约定,当在心中数到 k-1 时,下一个数字从0开始数。例如,当k=13时,栋栋和同学们报出的前几个数依次为:
1, 2, 4, 7, 11, 3, 9, 3, 11, 7。
游戏进行了一会儿,栋栋想知道,到目前为止,他所有说出的数字的总和是多少。
输入格式
输入的第一行包含三个整数 n,k,T,其中 n 和 k 的意义如上面所述,T 表示到目前为止栋栋一共说出的数字个数。
输出格式
输出一行,包含一个整数,表示栋栋说出所有数的和。
样例输入
3 13 3
样例输出
17
样例说明
栋栋说出的数依次为1, 7, 9,和为17。
数据规模和约定
1 < n,k,T < 1,000,000;
解题思路:
这道题是规律题目,多列举几项找出规律即可。
陈陈每次说的数字为a0+n*(n+1)/2;注意考虑%k否则最后一组数据会wa
#include<bits/stdc++.h>
using namespace std;
int main()
{
long long n,k,t; // 1<n,k,t<1,000,000
long long num = 1,sum = 0; //所以sum的可能值也有可能在1和1,000,000之间
cin>>n>>k>>t;
long long i = 1,j = n;
while(t--){
sum = sum + num;
num = (num + (i+j)*n/2)%k; //n+1到2n之间数的和加上原本的num 对k取余便是所求次数栋栋报的数
i = j+1; //第n+1个数
j = j+n; //第2n个数
}
cout<<sum;
return 0;
}