文章目录
- 一、基础练习
- 二、算法提高
- 三、历届试题
一、基础练习
1.fib数列
题目
Fibonacci数列的递推公式为:Fn=Fn-1+Fn-2,其中F1=F2=1。当n比较大时,Fn也非常大,现在我们想知道,Fn除以10007的余数是多少。
数据规模与约定
1 <= n <= 1,000,000。
解题思路
很明显,数据规模并不大,O(n)时间复杂度便可解决。
但如果数据规模非常庞大,我们可以利用到下面这张图的矩阵递推公式再根据矩阵快速幂解决:
解题代码
解法一(简单递推):时间复杂度O(n)
适用于数据量少于10^8的情况
#include <stdio.h>
const int MOD = 10007;
int main() {
int n;
scanf("%d", &n);
int a=1,b=1;
if(n<=2)printf("1");
else{
int tmp;
int i;
for(i=3;i<=n;i++) {
tmp = b;
b = (a+b)%MOD;
a = tmp;
}
printf("%d",b);
}
return 0;
}
解法二(矩阵快速幂):时间复杂度O(logn)
适用于数据量大于10^8的情况
//
// Created by Alone on 2021/11/19.
//
#include <bits/stdc++.h>
using namespace std;
typedef long long ll ;
//TODO To design a matrix class to solve this problem
class Matrix{
ll** date;
int m;
int n;
public: static const int MOD;
public:
Matrix(ll** rec,int n,int m):date(rec),n(n),m(m){
}//C format to init
Matrix():date(NULL),m(0),n(0){
} //aefault
Matrix(Matrix& b):n(b.n),m(b.m){
//copy struct
assert(b.date!=NULL && b.n>0 && b.m>0);
date = new ll*[n];
copy(b.date,b.date+n,date);
for(int i=0;i<n;i++){
date[i] = new ll[m];
copy(b.date[i],b.date[i]+m,date[i]);
}
}
~Matrix(){
//destruct
assert(date!=NULL && n>0 && m>0);
for (int i = n-1; i >=0 ; --i) {
delete [] date[i];
}
delete[] date;
}
Matrix& operator*(Matrix& b){
//TODO operator* to overload
assert(b.date!=NULL && date!=NULL && m==b.n);
ll tmp[n][b.m];
for(int i=0;i<n;i++){
for(int j=0;j<b.m;j++){
ll sum = 0;
for(int k=0;k<m;k++){
sum = (sum + date[i][k]*b.date[k][j])%MOD;
}
tmp[i][j] = sum;
}
}
this->m = b.m;
for(int i=0;i<n;i++){
for (int j = 0; j < m; ++j) {
date[i][j] = tmp[i][j];
}
}
return *this;
}
void init(){
//TODO initialized to unit matrix
assert(date!=NULL && n>0 && m>0);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if(i==j)date[i][j] = 1;
else date[i][j] = 0;
}
}
}
void quickPow(ll c){
//TODO quick pow for matrix
if(c==1||c<0)return;
if(c==0){
init();
return;
}
Matrix tmp(*this);
init();
while (c){
if(c&1)
*this = *this * tmp;
c >>= 1;
tmp = tmp*tmp;
}
}
void print(){
//TODO to print this matrix
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cout<<date[i][j]<<' ';
}
cout<<endl;
}
}
int get(int x,int y){
//TODO provide access to the outside
assert(date!=NULL && x<n && y<m);
return date[x][y];
}
};
const int Matrix::MOD = 1007;//TODO set the factor for mod operation
int main(){
ll c;
cin>>c;
ll** matrix = new ll*[2];
matrix[0] = new ll[2]{
1,1};
matrix[1] = new ll[2]{
1,0};
Matrix mat(matrix,2,2);
mat.quickPow(c-1);
ll** res = new ll*[2];
res[0] = new ll[1]{
1};
res[1] = new ll[1]{
1};
Matrix fib(res,2,1);
Matrix ret(mat*fib);
cout<<ret.get(1,0);
return 0;
}
2.闰年判断
题目
解题思路
只要挑选处闰年即可,闰年有个判断方式将其判断:
关于闰年的解释:
- 普通年份能被4整除,且不能被100整除的,是闰年。( 如2004年就是闰年)
- 世纪年份能被400整除的是闰年。( 如2000年是闰年,1900年不是闰年)
如果年份是闰年,那么它的二月份就会比平常多1天。
解题代码
#include<stdio.h>
int main(){
int n;
const char* res[]= {
"no","yes"};
scanf("%d",&n);
int index = 0;
if(n%400==0||(n%4==0&&n%100!=0))
index = 1;
fputs(res[index],stdout);
return 0;
}
3. 数列特征
题目
解题思路
求一个数组的最大值和最小值以及所有数字的和。。
解题代码
#include<iostream>
#include<algorithm>
#include<limits>
using namespace std;
int main(){
int n;
cin>>n;
int nums[n];
int mx=INT_MIN,mn=INT_MAX,sum = 0;
for(int i=0;i<n;i++){
cin>>nums[i];
mx = max(mx,nums[i]);
mn = min(mn,nums[i]);
sum += nums[i];
}
printf("%d\n%d\n%d",mx,mn,sum);
return 0;
}
4.查找整数
题目
解题思路
按照题目意思来就行,直接查找第一次出现的位置即可。
解题代码
解法一:C风格
#include <iostream>
using namespace std;
int main(){
int n,target;
int res = -1;
cin>>n;
int nums[n];
for(int i=0;i<n;i++){
cin>>nums[i];
}
cin>>target;
for (int i = 0; i < n; ++i) {
if(nums[i]==target){
res = i+1;
break;
}
}
cout<<res;
return 0;
}
解法二:C++风格
由于C++98不支持lamda表达式,所以需要把传入的函数单独写出来了。
#include <bits/stdc++.h>
using namespace std;
void input(int& a){
cin>>a;}
int main(){
int n,target,res;
cin>>n;
int nums[n];
for_each(nums,nums+n,input);
cin>>target;
res = find(nums,nums+n,target)-nums+1;
if(res>n)
res = -1;
cout<<res;
return 0;
}
C++11风格
#include <bits/stdc++.h>
using namespace std;
int main(){
int n,target;
int res;
cin>>n;
int nums[n];
for_each(nums,nums+n,[](int& a){
cin>>a;});
cin>>target;
res = find(nums,nums+