算法提高 数组求和

资源限制时间限制:1.0s   内存限制:256.0MB

问题描述  输入n个数,围成一圈,求连续m(m<n)个数的和最大为多少?

输入格式  输入的第一行包含两个整数n, m。第二行,共n个整数。

输出格式  输出1行,包含一个整数,连续m个数之和的最大值。

样例输入10 3
9 10 1 5 9 3 2 6 7 4

样例输出23

数据规模和约定  0<m<n<1000, -32768<=输入的每个数<=32767。

#include <bits/stdc++.h>
using namespace std;
int main()
{
	int a[2005]={0},N,M,max=0;
	//读入N:总的数据长度 和M:连续的数据长度 
	cin>>N>>M;
	//读入所有数据 
	for(int i=0;i<N;i++)
	{
		cin>>a[i];
	}
	//把连续的数据从头放到数据的最后(使之成为一个圈) 
	for(int i=0;i<M;i++)
	{
		a[N+i]=a[i];
	}
	//遍历数组 
	for(int i=0;i<N;i++)
	{
		int sum=0;
		//取和 取max 
		for(int j=i;j<i+M;j++)
		{
			sum+=a[j];
		}
		max = max<sum?(sum):(max);
	}
	cout<<max;
	return 0; 
} 

老了老了,啥也不会了。

高斯的日记

[问题描述]

大数学家高斯有个好习惯:无论如何都要记日记。

他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210

后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢?

高斯出生于:1777年4月30日。

在高斯发现的一个重要定理的日记上标注着:5343,因此可算出那天是:1791年12月15日。

高斯获得博士学位的那天日记上标着:8113

请你算出高斯获得博士学位的年月日。

#include <bits/stdc++.h>
using namespace std;
class data
{
	public:
		//年 
	int year;
		//月 
	int month;
		//日 
	int day;
	data()
	{
		this->year=1777;
		this->month=4;
		this->day=30;
	}
	int setyear()
	{
		this->year +=1;
	}
	int setmonth()
	{
		this->month +=1;
		if(this->month>12)
		{
			this->month = 1;
			this->setyear();
		}
	}
	int setday()
	{
		this->day+=1;
		int day = this->func();
		if(this->day>day)
		{
			this->day =1;
			this->setmonth();
		}
	}
	int func()//返回月份极限 
	{
		bool year = false; 
		int day = 0;
		//判断这一年的月份极限
		if(this->year%4==0&&this->year%100!=0)
		{
			//闰年 
			year = true;
		}else if(this->year%400==0)
		{
			//闰年
			year = true;
		}else
		{
			//不是闰年 
			year = false;
		} 
		switch(this->month)
		{
			case 1:
				day = 31;
				break;
			case 2:
				if(year)
				{
					day = 29;
				}else
				{
					day = 28;
				}
				break;
			case 3:
				day = 31;
				break;
			case 4:
				day = 30;
				break;
			case 5:
				day = 31;
				break;
			case 6:
				day = 30;
				break;
			case 7:
				day = 31;
				break;
			case 8:
				day = 31;
				break;
			case 9:
				day = 30;
				break;
			case 10:
				day = 31;
				break;
			case 11:
				day = 30;
				break;
			case 12:
				day = 31;
				break;
		}
		return day;
	}
};
int main()
{	
	//高斯出生 1777 4 30 
	data a;
	for(int i=1;i<8113;i++)
	{
		a.setday();
	}
	 
	cout<<a.year<<" "<<a.month<<" "<<a.day;

	return 0;
} 

用的C++的对象写的,面向过程也不难;答案:1799 7 16

3N+1问题

[问题描述]

考虑如下的序列生成算法:从整数 n 开始,如果 n 是偶数,把它除以 2;如果 n 是奇数,把它乘 3 加1。用新得到的值重复上述步骤,直到 n = 1 时停止。例如,n = 22 时该算法生成的序列是:

22,11,34,17,52,26,13,40,20,10,5,16,8,4,2,1

人们猜想(没有得到证明)对于任意整数 n,该算法总能终止于 n = 1。这个猜想对于至少 1 000 000内的整数都是正确的。

对于给定的 n,该序列的元素(包括 1)个数被称为 n 的循环节长度。在上述例子中,22 的循环节长度为 16。输入两个数 i 和 j,你的任务是计算 i 到 j(包含 i 和 j)之间的整数中,循环节长度的最大值。

[输入]

输入每行包含两个整数 i 和 j。所有整数大于 0,小于 1 000 000。

[输出]

对于每对整数 i 和 j,按原来的顺序输出 i 和 j,然后输出二者之间的整数中的最大循环节长度。这三个整数应该用单个空格隔开,且在同一行输出。对于读入的每一组数据,在输出中应位于单独的一行。

[样例输入]

1 10

100 200

201 210

900 1000

[样例输出]

1 10 20

100 200 125

201 210 89

900 1000 174

#include <bits/stdc++.h>
using namespace std;
static long long arr[1000005]={0}; 
int func(int a)
{
	//num记录循环节长 b记录初始值 
	long long num=0,b=a;
	while(b!=1)
	{
		//这里防止数组越界 因为b的值很难保证 然后判断数组中是否存在该数组  
		if(b<1000000&&arr[b]!=0)
		{
			//不等于0表示这个数已经求过循环节长 直接拿来用即可
			num += arr[b];
			return num;
		}
		//每次循环num加一 
		num++;
		//如果a是奇数 那么 a = a*3+1 否则 a = a / 2 
		b = (b&1)?(b*3+1):(b/2);	
	}
	//把该数组的键设置为求的循环节长,如果下次出现这个数,那么直接取得改数的循环节长

	arr[a] = num+1;
	return num+1;
}
int main()
{
	//类型保守全部定义为long long  防止越界 
	long long a=0,b=0,sum=0;;
	cin>>a>>b;
	for(int i=a;i<b;i++)
	{
		long long num = func(i);
		sum = sum<num?(num):(sum);
	}
	cout<<a<<" "<<b<<" "<<sum;
} 

时间复杂度不行可能不太够,从1到1000000大概需要3秒,擦边球,不太稳;(题目要求是3000毫秒)

生理周期

人 有 体 力 、 情 商 、 智 商 的 高 峰 日 子 , 它 们 分 别 每 隔 
23 天 、 28 天 和 33 天 出 现 一 次 。 对 于 每 个 人 , 我 们 想
知 道 何 时 三 个 高 峰 落 在 同 一 天 。 给 定 三 个 高 峰 出 现
的 日 子 p, e 和 i ( 不 一 定 是 第 一 次 高 峰 出 现 的 日 子 )
再 给 定 另 一 个 指 定 的 日 子 d , 你 的 任 务 是 输 出 日 子 d
之 后 , 下 一 次 三 个 高 峰 落 在 同 一 天 的 日 子 ( 用 距 离 d
的 天 数 表 示 ) 。 例 如 : 给 定 日 子 为 10 , 下 次 出 现 三
个 高 峰 同 一 天 的 日 子 是 12 , 则 输 出 2 。
#include <bits/stdc++.h>
using namespace std;
int main()
{
	//这个代码的精髓之处在于 巧妙的枚举,把不用的枚举跳过了。 
	//p,i,e,d,k	:	体力、情商、智商、给定的日志、天数 
	int p=0,i=0,e=0,d=0,k=0;
	cin>>p>>e>>i>>d;
	//循环增加天数 保证k-p(在给点日期之后) 是体力高峰 
	for(k=(d+1);(k-p)%23;k++);
	//k已经是体力高峰 现在保证k不仅是体力高峰还是情商高峰 
	for(;(k-e)%28;k+=23);
	//又保证了k是智商高峰(k+=23*28) 
	for(;(k-i)%33;k+=23*28);
	cout<<k-d;
}

完美立方

形 如 a3 = b3 + c3 + d3 的 等 式 被 称 为 完 美 立 方 等 式 。 倒 如 

123 = 63 + 83 + 103 。 编 写 一 个 程 序 , 对 任 给 的 正 整 数 N 

( N 100L 寻 找 所 有 的 四 元 组 ( a , b, c, d), 使 得 a3 = 

b3+ c3 + d3, 其 中 a,b,c,d 大 于 1 , 小 于 等 于 N , 且 

b<=c<=d

穷举法 但是要注意 a,b,c,d的范围

#include <bits/stdc++.h>
using namespace std;
int main()
{
	int n;
	cin>>n; 
	//a	:	[2,n] 
	for(int a=2;a<=n;a++)
	{
		//b	:	[2,a-1]
		for(int b=2;b<a-1;b++)
		{
			//c	:	[b,a-1]
			for(int c=b;c<=a-1;c++)
			{
				//d	:	[d,a-1]
				for(int d=c;d<=a-1;d++)
				{
					if(a*a*a==b*b*b+c*c*c+d*d*d)
					{
						cout<<a<<" "<<b<<" "<<c<<" "<<d<<endl;
					}
				}
			}
		}
	}
	
}

输入:24

输出:

6 3 4 5
12 6 8 10
18 2 12 16
18 9 12 15
19 3 10 18
20 7 14 17
24 12 16 20

算法训练 最大最小公倍数

已知一个正整数N,问从1~N中任选出三个数,他们的最小公倍数最大可以为多少。输入格式

输入一个正整数N。输出格式输出一个整数,表示你找到的最小公倍数。样例输入9样例输出504

数据规模与约定

1 <= N <= 106

别人的思路:若n 和 n-1和n-2 三个数 两两互质的话,那么结果就是这三个数的积。

根据数论知识:任意大于1的两个相邻的自然数都是互质的.

我们可以知道,当n是奇数时,n 和n-2都是奇数,n-1是偶数,那么他们三个的公约数肯定不是2,而因为这三个数是连续的,所以大于2的数都不可能成为他们或其中任意两个数的公约数了.结果就是他们三个的乘积.

而当n为偶数时,n(n-1)(n-2)肯定不行了,因为n和n-2都是偶数,那么只能将n-2改成n-3,即n(n-1)(n-3),如果这三个数两两互质那么肯定就是结果了.

但是因为n和n-3相差3,所以当其中一个数能被3整除时,另一个肯定也可以.而当其中一个不可以时,另一个肯定也不可以.而因为n为偶数,n-3为奇数,所以2不可能成为他俩的公因子。对于大于3的数,肯定就都不可能成为这三个数或者其中任意两个数的公约数了.因此只需再对3进行判断:

如果n能整除3,那么,n(n-1)(n-3)就肯定不行了,因为n和n-3有了公约数3,结果肯定小了,那么就只能继续判下一个即n(n-1)(n-4)而这样n-4又是偶数,不行继续下一个n(n-1)(n-5) = n^3 -6n^2 + 5n 而如果这个可以 那个其值肯定要小于(n-1)(n-2)(n-3) = n^3 -6n^2+11n-6(对于n>1来说都成立),而(n-1)(n-2)(n-3)由上一个奇数结论可知是一个符合要求的,因此到n-5就不用判断了。直接选答案为(n-1)(n-2)*(n-3);

而n不能整除3,那么结果就是n(n-1)(n-3),因为n和n-3都不能整除3,此时n-1能不能整除3都无关紧要了.而对于其它数 都是不可能的.上面已证.

代码

#include <bits/stdc++.h>
using namespace std;
//func	:	求两个数的最小公约数 
//最小公倍数 = x * y / func(x,y) 
int func(int x,int y)
{
	while(y>0)
	{
		int num=x%y;
		x=y;
		y=num;
	}
	return x;
}
int main()
{
	long long n=0,sum=0;
	cin>>n;
	if(n<=2)//特殊情况
	{
		sum=n;
	} 
	else if(n%2==1)//如果是奇数 
	{
		sum = n*(n-1)*(n-2);
	}else//如果是偶数 
	{
		if(n%3!=0&&func(func(n,n-1),n-3)==1)//如果不能被3整除 且互为质数 
		{
			sum = n*(n-1)*(n-3);
		}else//最坏结果 
		{
			sum = (n-1)*(n-2)*(n-3);
		}
	}
	cout<<sum;
	return 0;
} 

此代码蓝桥杯满分通过

打印大X

小明希望用星号拼凑,打印出一个大X,他要求能够控制笔画的宽度和整个字的高度。
为了便于比对空格,所有的空白位置都以句点符来代替。

要求输入两个整数m n,表示笔的宽度,X的高度。用空格分开(0<m<n, 3<n<1000, 保证n是奇数)
要求输出一个大X

例如,用户输入:
3 9
程序应该输出:

***.....***
.***...***.
..***.***..
...*****...
....***....
...*****...
..***.***..
.***...***.
***.....*** 

高是 9 宽是 11

再例如,用户输入:
4 21
程序应该输出

****................****
.****..............****.
..****............****..
...****..........****...
....****........****.... 
.....****......****.....
......****....****......
.......****..****.......
........********........ 
.........******.........
..........****..........
.........******.........
........********........
.......****..****.......
......****....****......
.....****......****.....
....****........****....
...****..........****...
..****............****..
.****..............****.
****................**** 

高是21 宽是 24

#include <iostream>
using namespace std;
int main(){
	//m	:	笔的宽度
	//n	:	X的高度 (0<m<n, 3<n<1000, 保证n是奇数)
	int m,n;
	cin>>m>>n;
	
	for(int i=0;i<n;i++){
		for(int j=0;j<n+m-1;j++)//矩形的高是 n 宽是 n+m-1 
		{
			for(int k=0;k<m;k++)//打印右斜  
			{
				if(i+k==j)
				{
					cout<<"*";
					goto This;//使用 goto语句 打印完*号则不打印其他 直接下一次循环 
				}	
			}
			for(int k=0;k<m;k++){
				if((i-k)+j==n-1)//打印左斜 
				{
					cout<<"*";
					goto This;
				}
			}
			cout<<".";//没有打印星号则打印句号 
			This: ;
		}
		cout<<"\n";
	} 
} 

代码满足上面两组数据

第几个幸运数

到x星球旅行的游客都被发给一个整数,作为游客编号。
x星的国王有个怪癖,他只喜欢数字3,5和7。
国王规定,游客的编号如果只含有因子:3,5,7,就可以获得一份奖品。

我们来看前10个幸运数字是:
3 5 7 9 15 21 25 27 35 45
因而第11个幸运数字是:49

小明领到了一个幸运数字 59084709587505,他去领奖的时候,
人家要求他准确地说出这是第几个幸运数字,否则领不到奖品。

请你帮小明计算一下,59084709587505是第几个幸运数字。

#include <iostream>
#include <math.h>
using namespace std;
int main(){
	//counut	:	计数 
	long long n=59084709587505,count=0;
	//3层循环
	
	for(int i=0;i<30;i++)
	for(int j=0;j<30;j++)
	for(int k=0;k<30;k++)
	{
		//n		:	59,084,709,587,505
		//3的29次方	:	68,630,377,364,883 
		//每一个乘数都大于n 考虑了自己为最大值 其他两个乘数为1的情况 
		if(pow(3,k)*pow(5,j)*pow(7,i)<=n)
		{
			count++;
		}
	}
	//当 i j k 都为0的时候   会产生一个无效结果“1” 
	cout<<count-1;	
} 

代码很简单,思路却很难,反向推导这题就很简单了

结果:1905

哪天返回

小明被不明势力劫持。后被扔到x星站再无问津。小明得知每天都有飞船飞往地球,但需要108元的船票,而他却身无分文。他决定在x星战打工。好心的老板答应包食宿,第1天给他1元钱。

并且,以后的每一天都比前一天多2元钱,直到他有足够的钱买票。请计算一下,小明在第几天就能凑够108元,返回地球。

#include <iostream>
using namespace std;
int main(){
	//m	:	小明打工挣得钱 从第一天开始 
	//n	:	小明的工资 
	//i	:	小明打工的天数 
	int m=1,n=1,i; 
	for(i=1;m<108;i++)
	{
		n=n+2;
		m+=n;
	}
	cout<<i;
} 

结果:11

STL初步

STL:(standard template library)标准模板库

包含一些常用的算法,如排序查找,还有常用的数据结构,如可变长数组、链表、字典等。

使用方便,效率高

要使用其中的算法,需要头文件#include <algorithm>