复旦大学计算机机试
笔者最近打算刷一下各大高校的机试题,暂时不详细分类(可能是夏令营,预推免,也可能是考研机试。很有可能不全)
就按照学校分类一下:
先从最简单的复旦刷起。
题目来源是一个名叫N诺的网站,大家可以上去自己玩玩。
可自行注册一个账号
邀请码为:noobdream
题一 :求众数
分析:计数类首先想到Hash表,发现没有数字的取值范围,就老老实实用map。
因为c++的map有序,遍历一次就可以找到较小的那个众数。(不要用unordered_map)
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin>>n;
int a[n];
map<int,int> m; //默认按照a[i]的大小排序
for(int i=0;i<n;i++){
cin>>a[i];
m[a[i]]++;
}
int maxcnt=0,res=0;
for(auto& it:m){
if(it.second>maxcnt){
res=it.first;
maxcnt=it.second;
}
}
cout<<res<<endl;
return 0;
}
题二:解一元一次方程
#include <iostream>
using namespace std;
int main()
{
string s;
cin>>s;
int sumx=0; //记录x前系数和
int sumd=0;//记录常数和
int num=0;
int flag=1; //正负号
int reve=1;//等号左右边
int len=s.size();
for(int i=0;i<len;i++){
if(isdigit(s[i])){
num=10*num+s[i]-'0';
}
if(s[i]=='x'){
if(num==0) num=1;//x前没有缺省系数
sumx+=num*flag*reve;
num=0;
}
if(s[i]=='+'){
sumd+=num*flag*reve;
flag=1; //正号
num=0; //为下一轮系数提取清零
}
if(s[i]=='-'){
sumd+=num*flag*reve;
flag=-1;
num=0;
}
if(s[i]=='='){
sumd+=num*flag*reve;
flag=1;
reve=-1;
num=0;
}
}
sumd+=num*flag*reve; //字符串末尾是没有结束符的,要再累计一次
if(sumx==0&&sumd==0) cout<<"infinite solutions"<<endl;
else if(sumx==0) cout<<"no solution"<<endl;
else cout<<"x="<<(double)-sumd/sumx<<endl; //sumx * x+sumd=0 ,x=-sumd/sumx
return 0;
}
题三:骨牌
#include <iostream>
using namespace std;
/*
n=1 , 1
n=2 , 2
n=3 , 3
n=4 , 5
发现规律:f(n)=f(n-1)+f(n-2) 也可以从排放形状入手
带入知道,f(6)=13
*/
int main()
{
int n;
cin>>n;
if(n<=2){
cout<<n<<endl;
return 0;
}
int pre2=1;
int pre1=2;
int ans;
for(int i=3;i<=n;i++){
ans=(pre1+pre2)%999983;
pre2=pre1;
pre1=ans;
}
cout<<ans<<endl;
return 0;
}
题四:集合交并
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,m;
cin>>n>>m;
int a[n],b[m];
set<int> s1;
for(int i=0;i<n;i++){
cin>>a[i];
s1.insert(a[i]);
}
set<int> s2,s3(s1);
for(int i=0;i<m;i++){
cin>>b[i];
if(s1.count(b[i])){ //s2用来存交集
s2.insert(b[i]);
}else{
s3.insert(b[i]);//s3用来存并集
}
}
cout<<s2.size()<<" "<<s3.size()<<endl;
return 0;
}
题五:约数求和
#include <iostream>
using namespace std;
/*
1 : 1
2 : 1 2
3 : 1 3
4 : 1 2 4
5 : 1 5
6 : 1 2 3 6
7 : 1 7
通过以上规律发现:1出现7/1次,2出现7/2次,3出现7/3次
i 出现 n/i次
*/
int main()
{
int n;
cin>>n;
long long ans=0;
for(int i=1;i<=n;i++){
ans+=(i)*(n/i);
}
cout<<ans<<endl;
return 0;
}
题六:求交点
#include <bits/stdc++.h>
using namespace std;
/*
y=(x-x1)*(y2-y1)/(x2-x1)+y1
y=(x-x3)*(y4-y3)/(x4-x3)+y3
解方程即可,但是注意,用乘积,少用除,防止出现除0. k1,k3不要算出来,展开了做
*/
int main()
{
int x1,y1,x2,y2;
int x3,y3,x4,y4;
cin>>x1>>y1>>x2>>y2;
cin>>x3>>y3>>x4>>y4;
int a0=(y2-y1)*(x4-x3)-(y4-y3)*(x2-x1);
if(a0==0){
cout<<"Parallel or coincident"<<endl;
}else{
int a1=(x4-x3)*(y2-y1)*x1;
int a2=(x2-x1)*(y4-y3)*x3;
int a3=(x4-x3)*(x2-x1)*(y3-y1);
double x=(double)(a1-a2+a3)/a0;
double y=(x-x1)*(y2-y1)/(x2-x1)+y1;
printf("%.2f %.2f",x,y);
}
return 0;
}
题七:长方形中的正方形
#include <iostream>
using namespace std;
/*
刚开始一看,有点儿像辗转相除的味道。
用递归写就好
递归函数recur(n,m)表示求的长方形长为n,宽为m的正方形个数
recur(n,m)=
1, n==m
1+recur(n-m,m),n>m
1+recur(n,m-n),n<m
递归三步走:
1.确定递归函数的意义
2.确定递归的方程
3.确定递归的初始条件
*/
int recur(int n,int m){
if(n==m) return 1;
else{
if(n<m) return 1+recur(n,m-n);
else return 1+recur(m,n-m);
}
}
int main()
{
int n,m;
cin>>n>>m;
cout<<recur(n,m)<<endl;
return 0;
}
题八:a与b得到c
#include <bits/stdc++.h>
using namespace std;
/*
送分不解释,如果是经过有限次四则运算,就变成了dfs的题了
*/
int main()
{
int a,b,c;
cin>>a>>b>>c;
set<double> s;
s.insert(a+b);
s.insert(a-b);
s.insert(b-a);
s.insert(a*b);
s.insert((double)a/b);
s.insert((double)b/a);
if(s.count(c)) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
return 0;
}
题九:相隔天数
#include <bits/stdc++.h>
using namespace std;
/*
日期类问题,常规模拟,注意相隔多少天,要取绝对值。
这里没说错误提示,我就没有对日期进行错误判断了。
*/
bool isLeapYear(int year){
return (year%4==0&&year%100!=0)||year%400==0;
}
int month_day[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int fromDays(int year,int month,int day){ //自1970:01:01
int days=0;
for(int i=1970;i<year;i++){
if(isLeapYear(i)) days+=366;
else days+=365;
}
for(int i=1;i<month;i++){
days+=month_day[i];
}
if(isLeapYear(year)&&month>2) days++;
days+=day;
return days;
}
int main()
{
string s;
cin>>s;
int len=s.size();
int year=0;
int month=0;
int day=0;
for(int i=0;i<len;i++){
if(i<4){
year=10*year+s[i]-'0';
}else if(i<6){
month=10*month+s[i]-'0';
}else{
day=10*day+s[i]-'0';
}
}
cout<<abs(fromDays(year,month,day)-fromDays(2019,2,5))<<endl;
return 0;
}
题十:最大连续子序列
#include <bits/stdc++.h>
/*
非常简单的一个dp,
dp[i]表示以a[i]结尾的最大连续子序列
dp[i]=
dp[i-1]+a[i],dp[i-1]>0
a[i] ,dp[i-1]<=0
最终答案res=max(res,dp[i])所有dp[i]的最大值
因为dp[i]只与dp[i-1]有关,于是可以压缩数组,为一个cur变量即可
*/
using namespace std;
int main()
{
int n;
cin>>n;
int a[n];
int cur=0;
int res=INT_MIN;
for(int i=0;i<n;i++){
cin>>a[i];
cur=cur>0?cur+a[i]:a[i];
res=max(cur,res);
}
cout<<res<<endl;
return 0;
}
题十一:有向树形态
#include <iostream>
using namespace std;
/*
n=0, f(0)=1;
n=1 ,f(1)=1
n=2, f(2)=2
n=3, f(3)=f(2)+f(1)*f(1)+f(2)
卡特兰数
f(n)=f(n-1)f(0)+f(n-2)f(1)+ ...+f(1)f(n-2)+f(0)f(n-1)
f(n)=(2n)!/((n)!*(n+1)!)
*/
long long f[21];
int main()
{
int n;
cin>>n;
f[0]=1;
f[1]=1;
for(int i=2;i<=n;i++){
for(int j=1;j<=i;j++){
f[i]+=f[i-j]*f[j-1];
}
}
cout<<f[n]<<endl;
return 0;
}
2020夏令营机试(图片来源网上)
题一:拓扑排序模板
/*
测试用例:
4
1 0
2 0
3 1
3 2
-1 -1//结束标志
*/
#include <bits/stdc++.h>
using namespace std;
vector<int> topo(int n,vector<vector<int>>& prerequist){
vector<int> res;
vector<int> indegrees(n); //入度表
vector<vector<int>> adj(n); //邻接表
queue<int> zero;//度数为0的队列
for(vector<int> tmp:prerequist){
indegrees[tmp[0]]++;
adj[tmp[1]].push_back(tmp[0]);
}
for(int i=0;i<n;i++){
if(indegrees[i]==0) zero.push(i);
}
while(!zero.empty()){
int tmp=zero.front();
zero.pop();
res.push_back(tmp);
for(int j=0;j<adj[tmp].size();j++){
if(--indegrees[adj[tmp][j]]==0) zero.push(adj[tmp][j]);
}
}
return res.size()==n?res:vector<int>{};
return res;
}
int main()
{
int n;
cin>>n; //输入没有进行太多处理,不是重点
vector<vector<int>> prerequist;
int x,y;
while(cin>>x>>y) {
vector<int> tmp;
tmp.push_back(x);
tmp.push_back(y);
prerequist.push_back(tmp);
if(x==-1){
prerequist.pop_back();
break;
}
}
vector<int> res=topo(n,prerequist);
for(int tmp:res){
cout<<tmp<<" ";
}
cout<<endl;
return 0;
}
题二:动规,等有时间再更新
备注:复旦这边题可以说,比较基础,大一的c语言学好都能做,有一些基础的数学找规律题。
可能是文理学校的缘故。