这是本人在半年前注册CSDN后原创的第一篇博客,算是在CSDN上的处女作吧,总结一些思路供以后翻阅。若这篇博文有幸被各位大佬过目,其中的很多不足还恳请各位多多指点。
在这篇blog中,我希望记录下对HDU数学专题训练部分题目知识点的一些思考。
一、Number Sequence
对于初学者,如果不仔细审题,可能会天真的开长度为100,000,000的数组再去遍历–>内存果断超限;亦或是想到使用数值交换的方法–>用时间超限替代了内存超限。。
那有什么idea能优化算法呢?
观察:f(1) = 1, f(2) = 1,
f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7.长的是不是很像斐波那契数列?
(在输入循环内部,A,B都可以视为常量)
思考:既然f(n)是对7取余得到的,那么f(n-1)和f(n-2)一定和f(n)类似,属于区间[0,6],所以至多到7*7=49时出现循环,因此我们只需要找到循环的长度 ,问题便能迎刃而解。
代码:
#include<iostream>
using namespace std;
int main()
{
int a[55],n,A,B,i;
while(cin>>A>>B>>n,A!=0,B!=0,n!=0) //输入循环
{
a[1]=1; //对数组前两个元素初始化
a[2]=1;
for(i=3;i<=49;i++) //最多只需遍历a[3]~a[49]即可找到循环节
{
a[i]=(A*a[i-1]+B*a[i-2])%7;
if(a[i]==a[2]&&a[i-1]==a[1]) //找到循环位置,可以跳出for了
break;
}
i-=2; //i-2存回i,表示整个循环的长度
if(n%i==0) //若n能整除循环长度,输出a[n]
n=i;
else //否则,n为整除i后的余值,即1到循环长度i中间的一个值
n%=i;
cout<<a[n]<<endl; //输出a[n]即为结果
}
}
二、FatMouse’ Trade
思考:读完题不难看出本题主要考察贪心算法,顺带分治思想。我们可以使用结构体存放食物与比率变量–>接收数据–>按照“JavaBean/猫粮”进行降序排列–>每次换比最大–>最后的交换的javaBean最大。
代码:
#include<iostream>
#include<algorithm>
#include<iomanip>
using namespace std;
struct trade
{
int j; //JavaBean的数量
int f; //猫粮数量
double rate; //一份猫粮能换到JavaBean的数量
}p[3005];
bool cmp(trade a,trade b)
{
return a.rate > b.rate;//sort函数降序规则
}
int main()
{
int M,N;//M磅猫粮,N个仓库房间
while(cin>>M>>N,M!=-1,N!=-1)//样例输入循环
{
for(int i=0;i<N;i++) //在第i个仓库房间,猫粮换食物
{
cin>>p[i].j>>p[i].f;
p[i].rate=(double)p[i].j/p[i].f; //兑换比率
}
sort(p,p+N,cmp);//降序排序
double sum=0;//定义老鼠吃到的总食物数
for(int i=0;i<N;i++)
{
if(M>p[i].f)
{ //如果剩下的猫粮大于换取某个仓库房间所需猫粮,则把仓库里面的全部换走
sum+=p[i].j;
M-=p[i].f;
}
else //最后剩下的猫粮换不了某个仓库房间里面的全部,则换取部分即可,并且结束了交易
{
sum+=p[i].rate*M;
M=0;
break;
}
}
printf("%.3lf\n",sum);//不太清楚为什么使用cout输出会提示答案错误。
//cout<<fixed<<setprecision(3)<<sum<<endl;
}
}
三、Fibonacci Again
观察:本题需要重点解决两个问题:
- 这个“斐波那契数列”可以直接遍历求解吗?–>显然不可以–>如何解决?
- 题目中n的最大值很大,如何建立数组?
思考:题目只要求判断F(n)是否能够被3整除,能否借助此条件简化计算?
代码:
#include<stdio.h>
#include<bits/stdc++.h>
using namespace std;
#define N 1000000
int a[N];
int main()
{
int n;
memset(a,0,sizeof(a));//memset函数申请内存建议数组暂且理解为动态建立数组吧
a[0]=7%3;a[1]=11%3;
while(cin>>n)
{
for(int i=2;i<=n;i++)
{
a[i]=(a[i-1]%3+a[i-2]%3)%3;//通过模操作限制了数值大小
}
if(a[n]==0)
{
printf("yes\n");
}
else
{
printf("no\n");
}
}
}
四、素数回文
评价:本题主要考察判断素数及回文数的能力,应该属于签到题。
代码:
#include <iostream>
#include <cstdio>
using namespace std;
int a[10000001];
int sushu(int n)//素数函数
{
if(n==2)return 1;
for(int i=2; i*i<=n; i++)
if(n%i==0)
return 0;
return 1;
}
int huiwen(int n)//回文函数
{
int m=0,t=n;
while(t)
{
m=m*10+t%10;
t/=10;
}
if(m==n)
return 1;
return 0;
}
int main()
{
int n,m;
while(cin>>n>>m)
{
for(int i=n;i<=m&&i<=9989899;i++)
if (huiwen(i)&&sushu(i))
printf("%d\n",i);
printf("\n");
}
}