第八周程序设计课解题报告
来源:互联网 发布:淘宝手机端免费视频 编辑:程序博客网 时间:2024/05/22 14:36
第八周程序设计课解题报告
下周期末考试啦,所以提前发布解题报告,留点时间给大家复习吧~
在写报告前:这周的题略微有点boss的感觉了,因为不再是单纯的暴力可行了,需要你去想如何优化才行了呢,其实这个也是日后程序设计的核心问题之一。很多问题直接暴力写的话很容易,但是往往会消耗(非常多)^n的时间或者空间。那么我们就要去找到题目潜在的规律去优化他,减少不必要的花销。如果不愿意开动脑子的话,当上ceo,迎娶白富美(高富帅)?哼哼,还是安心当一个只会打字的“码农”吧。
那么进入正题~
1000. Easy Program
题目大意:给出n个数,然后有m个询问,每次问原来的n个数当中第d个数的值是多少。
解:这个题目其实就是对数组的裸应用,真的不难。不过貌似有些同学是理解错了题意才跪的。我们读入询问d后直接输出a[d]即可(当然我的存储方式是[1,n]而非[0,n-1],使用后者的同学注意下标减一)
程序:
1001. Reversal
题目大意:首先给出n个数,然后给出m个操作,每次操作给出区间[x,y],假设原来n个数是放置在[1,n]上的,那么每次都把[x,y]这个区间进行翻转操作。最后再输出经过m次操作以后[1,n]上的数的数值。
解:不断进行交换操作就好了,但是我发现很多同学喜欢把交换的区间映射到[1,y-x+1]上,然后再进行翻转,其实这样不是不行,时间也不会慢,但是会使得你的下标比较容易写错。其实交换步骤变成x与y交换,然后x--,y++,直到x>y就好了。
哦对了,还有输出格式的问题,注意最后一个数后面是【没有空格】的,同时记得【换行】!
程序:
1002. The Highest Guy
题目大意:给出n个数,再给m个询问,每次询问第b个人到第n个人中最高的人的身高(区间[b,n]上的最大数)
解:哼哼哼,这题很简单啊输入,然后每次找区间最大的就好了。我交,卧槽,怎么tle了?
还记得我之前所讲的tle如何查错么,算一算如果出数据的人满怀恶意的话这题会怎么出数据卡你呢?自然是让你每次的询问都花费时间最大就好了。每次都询问1到n的最大值。而暴力寻找区间最大值的循环次数是区间长度(就是n),那么加上m次询问的话【时间复杂度】就是O(n*m),题目数据n,m,都去到10w,也就是说,最坏情况下,这题的复杂度达到100亿,然而我们的计算机一秒大概跑1亿次,而时间限制只有1秒。所以肯定会超时咯。
怎么优化呢?m次询问肯定少不了了,那么每次询问是否一定要n次呢?有没有非常神的办法呢?对于1个数,那么我们肯定1眼看出来了吧。那么对于多个数,能否做到1眼看出来呢?
注意题目有一个特殊性质,询问的是第b个人到n个人的最大值。那么对于b-1呢?是不是会有重复的东西?
当询问为b==n时,我们一眼望出来了,对于b==n-1时,是不是可以看两眼?对于b==n-2,望3眼?等等!我在看b==n-1时,如果把[n-1, n]的最大值保存下来放到help[n-1]里,是不是不用看[n-1,n]的那两眼了。好的,我们看了a[n-2],help[n-1]后,把最大值放入help[n-2]里,在观察[n-3,n]的时候,是不是只需要观察a[n-3]和help[n-2]就好了?如此类推,我们要完成整个help数组的记录,只需要2*n-1次即可了?实际上help[i]的意义就是记录了从第 i个数到第n个数的最大值。所以我们读入n后进行预处理得出help数组,询问的时候直接用上就好了,每次询问的处理显然是O(1)的。
那么原程序的时间复杂度已经下降到O(n+m)了(为啥少了东西?因为时间复杂度忽略常数)。这显然可以满足题目的要求了
对了,输入输出的次数多的时候记得不要用cin和cout,这两个东西非常非常非常非常非常慢!
程序:
解:很容易猜想到, 这个问题的关键是n个数中重复次数最多的数不要超过(n+1)/2个即可存在一种办法把数字都隔开。所以问题的关键在于找出最多的数有多少个。排序后统计?其实不必,因为观察到题目中有性质n个数的数值都在1~1000内,所以我们开一个数组f,f[i]表示i这个数字出现了几次即可。(这个办法其实也叫基数排序)详情看程序可能好理解一点。
程序:
解:这题为啥会超时的分析可以参见第三题。我们考虑如何优化。这题是否能够利用已有的信息使得询问的时候不用重复观察呢?我们先考虑如果询问特殊化把,每次都会询问[1,y],那么自然可以用一个数组预处理出[1,y]的和。但是题目要求的是[x,y]怎么办?其实,询问的区间是连续的,那么[x,y]是否等价于[1,y]-[1,x-1]呢?
程序:
最后想说两段话:
1.不知道有多少同学有去听周三晚林翰老师的信导课呢?在关于解题思路这一段,其实本周作业就有契合的地方。一是不必要详细证明自己的猜想 ,这便是第四题,我们得到一个用常识判断是对的策略,然而要数学证明就难了,有时候不必拘泥于这种问题。二是可以从小的数据出发去推出全局策略,我在第三题的优化步骤其实就是从小的出发,把问题特殊化,从区间为1,2,3(长度)慢慢推出来,再总结能用于一般化的策略,最后就完成了优化了。
2.时候看自己写的报告其实还是有不少错误的,如果有错,欢迎各种方式指正,如果有疑问或者想进一步了解的知识点,欢迎以各种方式找我。能帮助到大家,才是我写这份解题报告的最大快乐:)
在写报告前:这周的题略微有点boss的感觉了,因为不再是单纯的暴力可行了,需要你去想如何优化才行了呢,其实这个也是日后程序设计的核心问题之一。很多问题直接暴力写的话很容易,但是往往会消耗(非常多)^n的时间或者空间。那么我们就要去找到题目潜在的规律去优化他,减少不必要的花销。如果不愿意开动脑子的话,当上ceo,迎娶白富美(高富帅)?哼哼,还是安心当一个只会打字的“码农”吧。
那么进入正题~
1000. Easy Program
题目大意:给出n个数,然后有m个询问,每次问原来的n个数当中第d个数的值是多少。
解:这个题目其实就是对数组的裸应用,真的不难。不过貌似有些同学是理解错了题意才跪的。我们读入询问d后直接输出a[d]即可(当然我的存储方式是[1,n]而非[0,n-1],使用后者的同学注意下标减一)
程序:
#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdlib>
using namespace std;
#define SQR(x) ((x)*(x))
#define MIN(a,b) ((a<b)?a:b)
#define MAX(a,b) ((a>b)?a:b)
int main(){
int n, m, a[1111];
cin>>n>>m;
for (int i=1; i<=n; i++) cin>>a[i];
for (int i=1; i<=m; i++){
int tmp;
cin>>tmp;
cout << a[tmp] << endl;
}
return 0;
} 1001. Reversal
题目大意:首先给出n个数,然后给出m个操作,每次操作给出区间[x,y],假设原来n个数是放置在[1,n]上的,那么每次都把[x,y]这个区间进行翻转操作。最后再输出经过m次操作以后[1,n]上的数的数值。
解:不断进行交换操作就好了,但是我发现很多同学喜欢把交换的区间映射到[1,y-x+1]上,然后再进行翻转,其实这样不是不行,时间也不会慢,但是会使得你的下标比较容易写错。其实交换步骤变成x与y交换,然后x--,y++,直到x>y就好了。
哦对了,还有输出格式的问题,注意最后一个数后面是【没有空格】的,同时记得【换行】!
程序:
#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdlib>
using namespace std;
#define SQR(x) ((x)*(x))
#define MIN(a,b) ((a<b)?a:b)
#define MAX(a,b) ((a>b)?a:b)
int main(){
int n, m, a[1111];
cin>>n>>m;
for (int i=1; i<=n; i++) cin>>a[i];
for (int i=1; i<=m; i++){
int x, y, kok;
cin>>x>>y;
while (x<=y){
kok=a[x]; a[x]=a[y]; a[y]=kok;
x++; y--;
}
}
for (int i=1; i<=n; i++){
cout << a[i];
if (i<n) cout <<' ';
else cout << endl;
}
return 0;
} 1002. The Highest Guy
题目大意:给出n个数,再给m个询问,每次询问第b个人到第n个人中最高的人的身高(区间[b,n]上的最大数)
解:哼哼哼,这题很简单啊输入,然后每次找区间最大的就好了。我交,卧槽,怎么tle了?
还记得我之前所讲的tle如何查错么,算一算如果出数据的人满怀恶意的话这题会怎么出数据卡你呢?自然是让你每次的询问都花费时间最大就好了。每次都询问1到n的最大值。而暴力寻找区间最大值的循环次数是区间长度(就是n),那么加上m次询问的话【时间复杂度】就是O(n*m),题目数据n,m,都去到10w,也就是说,最坏情况下,这题的复杂度达到100亿,然而我们的计算机一秒大概跑1亿次,而时间限制只有1秒。所以肯定会超时咯。
怎么优化呢?m次询问肯定少不了了,那么每次询问是否一定要n次呢?有没有非常神的办法呢?对于1个数,那么我们肯定1眼看出来了吧。那么对于多个数,能否做到1眼看出来呢?
注意题目有一个特殊性质,询问的是第b个人到n个人的最大值。那么对于b-1呢?是不是会有重复的东西?
当询问为b==n时,我们一眼望出来了,对于b==n-1时,是不是可以看两眼?对于b==n-2,望3眼?等等!我在看b==n-1时,如果把[n-1, n]的最大值保存下来放到help[n-1]里,是不是不用看[n-1,n]的那两眼了。好的,我们看了a[n-2],help[n-1]后,把最大值放入help[n-2]里,在观察[n-3,n]的时候,是不是只需要观察a[n-3]和help[n-2]就好了?如此类推,我们要完成整个help数组的记录,只需要2*n-1次即可了?实际上help[i]的意义就是记录了从第 i个数到第n个数的最大值。所以我们读入n后进行预处理得出help数组,询问的时候直接用上就好了,每次询问的处理显然是O(1)的。
那么原程序的时间复杂度已经下降到O(n+m)了(为啥少了东西?因为时间复杂度忽略常数)。这显然可以满足题目的要求了
对了,输入输出的次数多的时候记得不要用cin和cout,这两个东西非常非常非常非常非常慢!
程序:
#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdlib>
using namespace std;
#define SQR(x) ((x)*(x))
#define MIN(a,b) ((a<b)?a:b)
#define MAX(a,b) ((a>b)?a:b)
int a[111111], maxx[111111];
int main(){
int n, m;
cin>>n>>m;
for (int i=1; i<=n; i++) scanf("%d", &a[i]);
maxx[n]=a[n];
for (int i=n-1; i; i--){
maxx[i]=MAX(a[i], maxx[i+1]);
}
int tmp;
for (int i=1; i<=m; i++){
scanf("%d", &tmp);
printf("%d\n", maxx[tmp]);
}
return 0;
}
1003. Yaroslav and Permutations
题目大意:给出n个数,问是否能通过若干次交换,反正就是能够把他变成相邻两个数不会相等即可。1003. Yaroslav and Permutations
解:很容易猜想到, 这个问题的关键是n个数中重复次数最多的数不要超过(n+1)/2个即可存在一种办法把数字都隔开。所以问题的关键在于找出最多的数有多少个。排序后统计?其实不必,因为观察到题目中有性质n个数的数值都在1~1000内,所以我们开一个数组f,f[i]表示i这个数字出现了几次即可。(这个办法其实也叫基数排序)详情看程序可能好理解一点。
程序:
#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdlib>
using namespace std;
#define SQR(x) ((x)*(x))
#define MIN(a,b) ((a<b)?a:b)
#define MAX(a,b) ((a>b)?a:b)
int a[111111], maxx[111111], f[1111];
int main(){
int n;
scanf("%d", &n);
memset(f, 0, sizeof(f));
for (int i=1; i<=n; i++){
int tmp;
scanf("%d", &tmp);
f[tmp]++;
}
bool flag=true;
for (int i=1; i<=1000; i++) if (f[i]>(n+1)/2){
flag=false; break;
}
if (flag) cout << "YES" << endl;
else cout << "NO" << endl;
return 0;
}
1004. Sum
题目大意:给出n个数,每次询问[x,y]这个区间内的所有数的和是多少。1004. Sum
解:这题为啥会超时的分析可以参见第三题。我们考虑如何优化。这题是否能够利用已有的信息使得询问的时候不用重复观察呢?我们先考虑如果询问特殊化把,每次都会询问[1,y],那么自然可以用一个数组预处理出[1,y]的和。但是题目要求的是[x,y]怎么办?其实,询问的区间是连续的,那么[x,y]是否等价于[1,y]-[1,x-1]呢?
程序:
#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdlib>
using namespace std;
#define SQR(x) ((x)*(x))
#define MIN(a,b) ((a<b)?a:b)
#define MAX(a,b) ((a>b)?a:b)
int a[111111], maxx[111111], f[1111];
int main(){
int n, m;
scanf("%d%d", &n, &m);
for (int i=1; i<=n; i++){
scanf("%d", &a[i]);
a[i]+=a[i-1];
}
a[0]=0;
int x, y;
for (int i=1; i<=m; i++){
scanf("%d%d", &x, &y);
printf("%d\n", a[y]-a[x-1]);
}
return 0;
} 最后想说两段话:
1.不知道有多少同学有去听周三晚林翰老师的信导课呢?在关于解题思路这一段,其实本周作业就有契合的地方。一是不必要详细证明自己的猜想 ,这便是第四题,我们得到一个用常识判断是对的策略,然而要数学证明就难了,有时候不必拘泥于这种问题。二是可以从小的数据出发去推出全局策略,我在第三题的优化步骤其实就是从小的出发,把问题特殊化,从区间为1,2,3(长度)慢慢推出来,再总结能用于一般化的策略,最后就完成了优化了。
2.时候看自己写的报告其实还是有不少错误的,如果有错,欢迎各种方式指正,如果有疑问或者想进一步了解的知识点,欢迎以各种方式找我。能帮助到大家,才是我写这份解题报告的最大快乐:)
0 0
- 第八周程序设计课解题报告
- 算法第八周解题报告
- 第七周程序设计课解题报告
- 第十周程序设计课解题报告
- 第十二周程序设计课解题报告
- 程序设计实习踩气球第八周《勇敢与鲁莽》解题报告&AC代码
- 第八届北航程序设计大赛网络预赛解题报告
- 第十一周程序设计课作业解题报告
- 第十四周程序设计课解题报告
- 第十五周程序设计作业解题报告
- C2第八次解题报告
- 第八届湖南省大学生程序设计大赛 - 笑不语@USC 随笔,感想,解题报告
- 第八届湖南省大学生程序设计大赛 - 笑不语@USC 随笔,感想,解题报告
- “光庭杯”第五届华中北区程序设计邀请赛 暨 WHU第八届程序设计竞赛(部分解题报告)
- C++程序设计实验报告(五十四)---第八周任务二
- C++程序设计实验报告(五十五)---第八周任务三
- C++程序设计实验报告(五十六)---第八周任务四
- 多校第八场解题报告
- jetty访问jsp页面出现异常:org.apache.jasper.JasperException: PWC6345: A full JDK (not just JRE) is required解决
- 又开始写博客了
- 为啥我的程序超时?随便谈谈时间复杂度
- Spring MVC
- 注册表被修改的常见问题
- 第八周程序设计课解题报告
- struts2 package 属性说明
- sdut2408 Pick apples
- LeetCode Nth Highest Salary
- 第八周的药之程序风格
- ZOJ 3866 Cylinder Candy
- HDU 4089 Activation 概率dp
- Hibernate之CRUD工具类
- C++中一种十分有用的容器vector