1.查询子序列和
对N个整数的序列,查询子序列和∑k=ijAk , (1≤i,j≤N).
输入格式:
第1行,两个整数:N和Q,表示整数的个数和查询的次数,1≤N≤100000,0≤Q≤100000.
第2行,N个用空格分开的整数 x , │x│≤20000.
第3至Q+2行,每行两个整数i和j,表示所求子序列和的区间[i,j],1≤i≤j≤N,保证所有区间都合法。
输出格式:
Q行,每行一个整数,表示相应子序列的和
代码长度限制-16 KB
时间限制-200 ms
内存限制-2 MB
问题:常规算法当Q较大时会运行超时
思路:利用数组保存求和结果,每多加一项就sum[i++]=sum[i-1]+x,输出时sum[r]-sum[l-1]即可
long long sum[100010] = { 0 };
for (int i = 1; i <= N; i++)
{
long long x;
scanf("%lld", &x);
sum[i] = sum[i - 1] + x;
}
需要注意的是,提交代码时利用scanf运行能通过,cin会超时。
完整代码:
#include<iostream>
#include<cstdio>
using namespace std;
int N, Q;
long long sum[100010] = { 0 };
int main()
{
cin >> N >> Q;
for (int i = 1; i <= N; i++)
{
long long x;
scanf("%lld", &x);
sum[i] = sum[i - 1] + x;
}
for (int i = 1; i <= Q; i++)
{
int l, r;
scanf("%d%d", &l, &r);
printf("%lld", sum[r] - sum[l - 1]);
if (i != Q)
printf("\n");
}
return 0;
}
2.数列查询
已知数列的通项公式为:
f(n) = f(n-1)*11/10,f[1]=10.
通项从左向右计算,*和/分别表示整数乘法和除法。
现在,要多次查询数列项的值。输入格式:
第1行,1个整数q,表示查询的次数, 1≤q≤10000.
第2至q+1行,每行1个整数i,表示要查询f(i)的值。输出格式:
q行,每行1个整数,表示f(i)的值。查询的值都在32位整数范围内。
代码长度限制-16 KB
时间限制-10 ms
内存限制-1 MB
问题:常规递归算法会运行超时
思路:利用已经计算出的f(n)作为递归出口
int a[10000]={0};
if(n==1) return a[1];
else {
if(a[n]>0)return a[n];
else {a[n]=f(n-1)*11/10;return a[n];}
}
注意:可以利用一个循环,每输入一个数字就求出结果。
完整代码:
#include<stdio.h>
int a[10000]={0};
int f(int n){
if(n==1) return a[1];
else {
if(a[n]>0)return a[n];
else {a[n]=f(n-1)*11/10;return a[n];}
}
}
int main(){
int q,k;
scanf("%d",&q);
a[1]=10;
for(int i=1;i<=q;i++){
scanf("%d",&k);
printf("%d\n",f(k));
}
return 0;
}
3.估算运行空间
一个代码的存储部分如下:
int n,m;
int vertex[MAXN];
int g[MAXN][MAXN];
假设:在32为操作系统(OS)下运行,只考虑如上代码段,不考虑程序自身存储空间等,给定MAXN,计算该算法的运行空间,其中空间的单位为Mb,1Mb = 10^6字节(Byte)。
输入格式:
一行,包含1个正整数,表示算法输入的最大取值MAXN,n <=10^6.
输出格式:
一个整数,表示该算法的运行空间估算值,该值向上取整。
代码长度限制-16 KB
时间限制-400 ms
内存限制-64 MB
没有太大难度,求出空间/1e6即可,记得向上取整
#include<iostream>
using namespace std;
int main()
{
long long n, m;
cin >> n;
m = 4 * n + 4 * (n * n)+8;
if (m % 1000000 != 0)
{
m = m / 1000000 + 1;
}
else m = m / 1000000;
cout << m;
return 0;
}
4.估算运行时间
一个算法的基本运算:交换两个整数的值,时间复杂度为 T = n(n-1)/2。其中,交换使用3个赋值运算实现。
假设:交换运算时间超过整个算法的1/3,在单核通用计算机上运行,给定n的最大取值,估算该算法的最大运行时间,时间向上取整为秒。
输入格式:
行,包含1个正整数n,表示算法输入的最大取值,n <=10^8。
输出格式:
个整数,表示该算法的最大运行时间的估计.
代码长度限制-16 KB
时间限制-400 ms
内存限制-64 MB
这道题主要是意思不太好理解,赋值运算时间复杂度已知,一个交换有三个赋值语句,交换占算法时间的1/3,求算法运行时间(记得除1e8,向上取整)
#include<iostream>
using namespace std;
int main()
{
long long n;
long long t;
cin >> n;
t = n * (n - 1) / 2;
t = t * 9;
if (t % 100000000 == 0)
t = t / 100000000;
else
t = t / 100000000 + 1;
cout << t;
}
5.冰雹猜想
70年代中期,美国各所名牌大学校园内,人们都像发疯一般,夜以继日,废寝忘食地玩弄一种数学游戏。这个游戏十分简单:任意写出一个正整数N,并且按照以下的规律进行变换:
如果是个奇数,则下一步变成3N+1。
如果是个偶数,则下一步变成N/2。
不单单是学生,甚至连教师、研究员、教授与学究都纷纷加入 。为什么这种游戏的魅力经久不衰?因为人们发现,无论N是怎样一个数字,最终都无法逃脱回到谷底1。准确地说,是无法逃出落入底部的4-2-1循环,永远也逃不出这样的宿命。
这就是著名的“冰雹猜想”。
给出一个正整数N,计算全部变换过程(称作“雹程”)的步数。
输入格式:
一行,1个正整数N,N <=10^6.输出保证合法。
输出格式:
一个整数,为所求步数。
代码长度限制-16 KB
时间限制-400 ms
内存限制-64 MB
很简单,记得输入是long long类型即可
#include<iostream>
using namespace std;
int main()
{
long long N;
int sum=0;
cin >> N;
while (N != 1)
{
if (N % 2 == 0)
N = N / 2;
else
N = (3 * N + 1);
sum++;
}
cout << sum;
}
6.素数
判断正整数 N 是否为素数。
规定:自然数1既不是素数也不是合数。
输入格式:
一行,包含1个正整数N,N <= 2^31 - 1.输入保证合法。
输出格式:
一行。如果N为素数,输出Yes,否则输出No.
代码长度限制-16 KB
时间限制-5 ms
内存限制-64 MB
问题:利用常规n/2会运行超时
思路:让i循环到根号n
for (i = 2; i <= sqrt(N); i++)
{
if (N % i == 0)
{
cout << "No";
return 0;
}
}
完整代码:
#include<iostream>
#include<math.h>
using namespace std;
int main()
{
long long N;
int i;
cin >> N;
if (N == 1)
{
cout << "No";
return 0;
}
for (i = 2; i <= sqrt(N); i++)
{
if (N % i == 0)
{
cout << "No";
return 0;
}
}
cout << "Yes";
return 0;
}
大二代码小白初学数据结构,用博客来记录作业笔记与学习过程,方法大都较为常规,如有错误恳请指正!