NOIP2017 普及组 蒟蒻的题解报告
来源:互联网 发布:维基百科数据库 使用 编辑:程序博客网 时间:2024/06/05 19:23
前言
这是本蒟蒻在CSDN的第一篇题解报告
第一次就写NOIP鸭梨很大
本蒟蒻在PJ中获得了290的成绩,几乎可以说是压线省一(ZJ 分数线280)
所以我也花了一些功夫来研究本次的四道题目
希望明年TG可以获得比较好的成绩(省二什么的)
进入正文——
T1 成绩
原题链接
这道题目从难度上说是一道刚学OI的新手的练习题,难度为0
事实上,还是有一点东西需要注意的,而很多OI选手都不知道
那么我个人在学OI之前是先学的python,用的教材是Sande父子的《父与子的编程之旅》
其中在开头就讲到了关于 精度 的问题
比如下面这段伪代码:
cin >> a >> b >> c;cout << a*0.2+b*0.3+c*0.5 << endl;
如果直接这么写,本机上测试应该不会有任何问题,但是要是放在linux系统下(例如今年的CCF评测机),可能会这样:
输入: 100 100 100
输出: 99.999999997
这也就是为什么今年有那么多人申诉从而迫使CCF改变评测机的设置
本蒟蒻代码如下:
#include<iostream>using namespace std;int a,b,c;int main(){ cin >> a >> b >> c; a/=10; b/=10; c/=10; a*=2; b*=3; c*=5; cout << a+b+c; return 0;}
这样写就不会有任何问题,所以本蒟蒻一开始就是100 (省掉了50申诉费)
T2 图书管理员
原题链接
当我从考场里出来时,很多人都说他们用的是string
而用了 取模求最后几位 的只有我和另外一个同学(我们队)
当时就有人有疑问了:形如00005的数怎么办???
我当时也懵了,好在CCF并没有这样的数据
而使用这种算法是建立在一个前提上的:把数的位数告诉你,否则效率不如字符串
而如果把数的位数告诉了你,而数的位数比较大,那么使用这种算法就会比较快(超过longlong的除外)
鉴于 位数
举个栗子:
比如 图书编码为
需求码长度为
这时的
而
代码如下:
#include<cstdio>#include<iostream>#include<algorithm>using namespace std;int n,m,q[15]={0,10,100,1000,10000,100000,1000000,10000000,100000000},a[1005];//预处理int main(){ cin >> n >> m; for(int i=1;i<=n;i++) cin >> a[i]; sort(a+1,a+n+1);//先排序保证每次取得最优解 for(int i=1;i<=m;i++) { int x,y; bool fg=false; cin >> x >> y; for(int j=1;j<=n;j++) if(a[j]%q[x]==y)//由于排了序,所以符合条件的第一个必然是最优解 { fg=true;//记录已取到答案 cout << a[j] << endl;//输出 break;//跳出本层循环即可 } if(!fg) cout << -1 << endl;//如果没有找到解输出-1 } return 0;}
T3 棋盘
从这里开始的题目就比较难了,做好准备!
原题链接
我本人在T3打的是dfs暴力
当时获得了60分,如果加一个记搜的话70分
那么这题正解是什么呢?
大致看下来有三种解法:
1. 玄学记搜dfs
2. 靠谱坚实bfs
3. 看不懂的最短路
而 dp 写法是不行的,因为这题有后效性(不明显)
我在一位dalao的帮助下写出了第1种方法,接下来讲讲做法
首先是变量:
核心变量是一个三位数组
(这不是dp是记搜)
别的应该都比较好理解
代码如下:
#include<cstdio>#include<iostream>#include<algorithm>#include<string>#include<cstring>using namespace std;int m,n,a[105][105],xx,yy,zz,ans=2147400000,f[105][105][3];//前面解释过的f数组,别的都不多说了bool fg;void dfs(int x,int y,int now,int sum,bool mag){ //xy为当前坐标,now为当前格子的颜色,sum为当前花费,mag为是否使用魔法 if(x>m || y>m || x<1 || y<1) return;//如果越界则退出 else if(a[x][y]==0)//如果当前格子没有颜色 { if(mag) return;//使用过魔法就退出 sum+=2;//否则加上改变的花费 if(f[x][y][1]>sum+now-1)//记搜大法 变相表现走到颜色0的花费 { f[x][y][1]=sum+now-1; dfs(x+1,y,1,sum+now-1,1); dfs(x,y+1,1,sum+now-1,1); dfs(x-1,y,1,sum+now-1,1); dfs(x,y-1,1,sum+now-1,1); } if(f[x][y][2]>sum-now+2)//同上,表现走到颜色1的花费 { f[x][y][2]=sum-now+2; dfs(x+1,y,2,sum-now+2,1); dfs(x,y+1,2,sum-now+2,1); dfs(x-1,y,2,sum-now+2,1); dfs(x,y-1,2,sum-now+2,1); } } else//如果有颜色 { if(a[x][y]!=now) sum+=1;//如果当前格和上一个不一样就加1花费 if(sum>=f[x][y][0]) return;//记搜大法 f[x][y][0]=sum;//赋值记搜数组 dfs(x+1,y,a[x][y],sum,0); dfs(x,y+1,a[x][y],sum,0); dfs(x-1,y,a[x][y],sum,0); dfs(x,y-1,a[x][y],sum,0);//无脑dfs }}int main(){ memset(f,0x3f3f3f,sizeof(f)); cin >> m >> n; for(int i=1;i<=n;i++) { cin >> xx >> yy >> zz; a[xx][yy]=zz+1; //鉴于有颜色0,为了不赋初值故如此 } dfs(1,1,a[1][1],0,0);//dfs if(a[m][m]==0) ans=min(f[m][m][1],f[m][m][2]); else ans=f[m][m][0];//存答案 if(ans>=10000000) cout << -1; else cout << ans;//输出 return 0;}
T4 跳房子
原题链接
这道题目难度极高(怎么说也是蓝题)
做法是 dp+二分+单调队列优化
非常烦人!
考试时本蒟蒻因为时间(脑子)不够 写的是枚举+错误的dp
骗到30分(没这30我就GG了)
那么有人问了:单调队列怎么用?
大家都知道,单调队列会维护队首(这题是最大),那么我们就可以将 可以跳到的范围 内的最大值维护在队首,降低大量复杂度
大家可以自己手打一个双向队列(数组模拟)
本蒟蒻就只好用STL大法的deque了
推荐一篇博客:justmeh大佬的单调队列初步
代码可能比较难理解,但是原理解释得很透彻
顺便给道例题:Luogu P1886 滑动窗口
二分和dp就不多说了,大家都看得出来
代码如下:
#include<cstdio>#include<queue>#include<cstring>#include<algorithm>using namespace std;deque <int> q;//STL大法好!!!long long n,d,k,f[500005];long long a[500005],w[500005];//a存位置,w存分数inline int read(){ int sum=0,fu=1; char ch=getchar(); while(ch<'0' || ch>'9') { if(ch=='-') fu=-1; ch=getchar(); } while(ch>='0' && ch<='9') { sum=(sum << 3)+(sum << 1)+(ch ^ 48); ch=getchar(); } return sum*fu;}//读入优化bool DP(int x)//dp本体{ int t1=d-x > 1 ? d-x : 1 ,t2=d+x;//计算最近最远跳跃距离 while(!q.empty()) q.pop_back();//清空队列 memset(f,0,sizeof(f));//清空数组 int t=0;//现在将要入队的点 for(int i=1;i<=n;i++) { while(a[i]>=t1+a[t])//如果足够远 { while(!q.empty() && f[t]>=f[q.back()]) q.pop_back(); q.push_back(t);//进队,维护单调队列 t++; } while(!q.empty() && a[i]>a[q.front()]+t2) q.pop_front(); //把太远跳不到的出队 if(q.empty()) f[i]=-9999999999;//如果队列空了,存入负无限 else f[i]=f[q.front()]+w[i];//否则存入当前最大值 if(f[i]>=k) return 1;//如果得到解返回真 } return 0;//如果一直都没得到解返回假}int main(){ long long ans=9999999999;//最好设这么大,否则会WA n=read(); d=read(); k=read(); int S=0; for(int i=1;i<=n;i++) { a[i]=read(); w[i]=read(); } int L=0,R=a[n]; while(L<=R)//二分开始 { long long mid=L+R >> 1;//mid代表改造花的金币 bool res=DP(mid);//存下是否能够得到k分 if(res)//如果可以 { ans=min(ans,mid);//存答案 R=mid-1; } else L=mid+1; } printf("%lld",ans);//输出即可 return 0;}
小结
这次比赛题目 T1、T2 送分,T3、T4对思考要求比较高,本蒟蒻也没有透彻理解,而这次拿到1=也是运气居多,可见我们要走的路还有很长
各位,NOIP2018 TG见。
原创 By Venus
写的不好大佬轻喷
- NOIP2017 普及组 蒟蒻的题解报告
- NOIP2017普及组题解
- NOIP2017普及组题解
- NOIP2017普及组题解
- NOIP2010 普及组 蒟蒻的题解报告
- NOIP2017普及组T1题解
- NOIP2017普及组T2题解
- NOIP2017普及组复赛题解
- NOIP2017普及组解题报告
- NOIP2017普及复赛 (~~题解)
- NOIP2017普及组复赛解题报告
- noip2016普及组题解报告
- noip2017解题报告题解
- NOIP2017普及组★总结★题解★规划
- NOIP2015普及组第四题解题报告
- NOIP2017普及组
- [NOIP2017普及组]棋盘
- 【NOIP2017普及组】棋盘
- Developing with Couchbase Server.pdf 英文原版 免费下载
- HttpClient在安卓中的应用
- 前端小技巧--三级联动
- 计算机会议排名等级
- Android service 不是进程也不是线程
- NOIP2017 普及组 蒟蒻的题解报告
- OCAOCP Java SE 7 Programmer I
- 侧滑菜单之ResideMenu
- 分答项目_知识点_微擎web页面
- 抽象类和接口的区别
- 归一化、标准化区别的通俗说法
- 化方程为一般式
- JSP总结
- 转载linux相关