第一届『Citric杯』NOIP提高组模拟赛 题解
2012-08-21 13:19
260 查看
【官方题解】第一届『Citric杯』NOIP提高组模拟赛 题解
第一题 柠檬超市
这题是本次模拟赛的送分题。做法显然。
但是注意此题有一个陷阱:
注意W和C的规模都是10^9,所以如果直接用double来存储性价比会挂精度(999999999/1000000000和999999998/999999999的差距只有10^-18,这么微小的差距double是分辨不出来的)
正确做法是,把除法的除数移项,转化成乘法,然后用int64或long long。
另外一个讨巧的方法是用long double或extended来存储性价比,因为long double/extended的有效数字比double更多,所以勉强能不挂精度。
很不幸,如果挂精度的话就只有20分了。
需要的知识:模拟
代码长度 小于0.5KB.
第二题 柠檬的坦克游戏
此题20%数据的做法显然,直接照着题目要求模拟即可,O(N^3)
此题40%数据做法也比较简单,有两个做法:
1.对20%的做法进行改进,预先对所有的武器按D值排序,这样查找有没有更优的武器时直接查找D值比它大的就行了,时间复杂度可以证明被均摊到了O(N^2)。
2.依然预先对所有武器按D值从小到大排序,然后每次扫一遍,用一个单调栈维护即可,只要遇到R值比栈顶大就弹栈,否则入栈。扫一次就能得出一组,也是O(N^2)的。
此题满分做法是对上一个做法的改进。
仔细观察题目的流程,我们可以发现一个更优的做法。
首先我们发现同一组内的武器,按D值从大到小排序后,R值必然也是从小到大的。
而且我们发现,如果一件武器A的D值比另一件武器B的D值大,那么武器B不会影响到武器A的分组。
于是考虑把武器按D值从大到小排序,然后逐个加入武器,并为新加入的武器找到合适的组。因为在新加入一件武器之前,我们已经加入了所有D值更大的武器,而剩下的武器都不会影响当前武器的分组,所以现在得出的组号就是最终的组号。
假设D值最大的前x个武器已经全部加入组,而且现在已经有k组了,定义第i组里最大的R值为maxR(i),那么我们发现maxR(i)必然随i递减。
我们考虑加入第x+1个武器,我们发现,按照题目要求,这件武器必然会加入到第i组,i是最小的让maxR(i)<D成立的i值。
于是我们直接用数组存储所有组的maxR,新加入武器时二分查找到加入位置,然后更新对应的那个maxR即可。
时间复杂度O(NlgN)
需要的知识: 二分查找
代码长度 0.5KB ~ 1KB
第三题 柠檬当上了JC局长!
此题20%数据做法显然,直接爆搜即可。
想要得到更高的分数,首先我们要观察一些性质。
首先,我们发现罪犯的逃跑方式,实际是在给定图的点1的最短路径图上,从根开始,每次随机选择一个孩子移动,移动到叶子后如果还没被抓到就失败了。
而且,题目保证了从结点1到任意结点的最短路唯一,所以点1的最短路径图实际是一棵树!
于是,我们可以先做一次点1为源点的dijkstra或直接floyd,把点1的最短路径树建立出来。
然后问题就变成了,给定一棵树,你可以在树的结点上设置埋伏,以获得最高的抓捕成功几率。
我们发现一个非常显然的动态规划状态:dp[i][j]在点i为根的子树内共设置j个**,罪犯到达i后能获得的最高成功率。
那么50%数据的做法就非常显然了。
因为我们保证了任意一个结点度数不超过3,也就是每个结点最多只有2个孩子(根可能有3个孩子,不过这不会影响复杂度)
于是我们转移时,暴力枚举根以及其孩子分别分配到了多少个人进行埋伏。时间复杂度是O(N*P^4)
进一步思考,很容易得出满分做法。
我们发现,在一个结点上所要进行的分配人力的任务,实际是一个背包。于是在结点上做一个背包即可。
但是注意这个背包是以当前结点的所有的孩子做背包,然后因为当前节点抓捕失败后才能往孩子走,所以当前结点要枚举埋伏人数,才能得出最终的答案。
时间复杂度是O(N*P^2)
需要的知识:最短路径算法、最短路径树的概念、背包DP、树形DP
代码长度 1KB~2KB
数据和标程的下载地址: http://pan.baidu.com/share/link?shareid=3747&uk=2249476017
最后,感谢诸位的参与。感谢Vani,kAc,applepi等人的验题
PS:以上是sillycross大神的官方题解,他写的是pascal,我等c++支持者便是抓瞎,当然,我真的没看他的代码。因为看了也不懂。
以下是我自己写的c++的代码,大神不要BS我啊!
第一题:我这个蒟蒻,一看大水,果断5分钟敲完交了,没想精度问题,果断20分。。
View Code
总体来说这套题的难度还是低于NOIP的,(这么低分,你也好意思说!),应该得到的教训就是,简单题只要做了就必须拿满分!还有就是,思考完善了再动手敲代码!
第一题 柠檬超市
这题是本次模拟赛的送分题。做法显然。
但是注意此题有一个陷阱:
注意W和C的规模都是10^9,所以如果直接用double来存储性价比会挂精度(999999999/1000000000和999999998/999999999的差距只有10^-18,这么微小的差距double是分辨不出来的)
正确做法是,把除法的除数移项,转化成乘法,然后用int64或long long。
另外一个讨巧的方法是用long double或extended来存储性价比,因为long double/extended的有效数字比double更多,所以勉强能不挂精度。
很不幸,如果挂精度的话就只有20分了。
需要的知识:模拟
代码长度 小于0.5KB.
第二题 柠檬的坦克游戏
此题20%数据的做法显然,直接照着题目要求模拟即可,O(N^3)
此题40%数据做法也比较简单,有两个做法:
1.对20%的做法进行改进,预先对所有的武器按D值排序,这样查找有没有更优的武器时直接查找D值比它大的就行了,时间复杂度可以证明被均摊到了O(N^2)。
2.依然预先对所有武器按D值从小到大排序,然后每次扫一遍,用一个单调栈维护即可,只要遇到R值比栈顶大就弹栈,否则入栈。扫一次就能得出一组,也是O(N^2)的。
此题满分做法是对上一个做法的改进。
仔细观察题目的流程,我们可以发现一个更优的做法。
首先我们发现同一组内的武器,按D值从大到小排序后,R值必然也是从小到大的。
而且我们发现,如果一件武器A的D值比另一件武器B的D值大,那么武器B不会影响到武器A的分组。
于是考虑把武器按D值从大到小排序,然后逐个加入武器,并为新加入的武器找到合适的组。因为在新加入一件武器之前,我们已经加入了所有D值更大的武器,而剩下的武器都不会影响当前武器的分组,所以现在得出的组号就是最终的组号。
假设D值最大的前x个武器已经全部加入组,而且现在已经有k组了,定义第i组里最大的R值为maxR(i),那么我们发现maxR(i)必然随i递减。
我们考虑加入第x+1个武器,我们发现,按照题目要求,这件武器必然会加入到第i组,i是最小的让maxR(i)<D成立的i值。
于是我们直接用数组存储所有组的maxR,新加入武器时二分查找到加入位置,然后更新对应的那个maxR即可。
时间复杂度O(NlgN)
需要的知识: 二分查找
代码长度 0.5KB ~ 1KB
第三题 柠檬当上了JC局长!
此题20%数据做法显然,直接爆搜即可。
想要得到更高的分数,首先我们要观察一些性质。
首先,我们发现罪犯的逃跑方式,实际是在给定图的点1的最短路径图上,从根开始,每次随机选择一个孩子移动,移动到叶子后如果还没被抓到就失败了。
而且,题目保证了从结点1到任意结点的最短路唯一,所以点1的最短路径图实际是一棵树!
于是,我们可以先做一次点1为源点的dijkstra或直接floyd,把点1的最短路径树建立出来。
然后问题就变成了,给定一棵树,你可以在树的结点上设置埋伏,以获得最高的抓捕成功几率。
我们发现一个非常显然的动态规划状态:dp[i][j]在点i为根的子树内共设置j个**,罪犯到达i后能获得的最高成功率。
那么50%数据的做法就非常显然了。
因为我们保证了任意一个结点度数不超过3,也就是每个结点最多只有2个孩子(根可能有3个孩子,不过这不会影响复杂度)
于是我们转移时,暴力枚举根以及其孩子分别分配到了多少个人进行埋伏。时间复杂度是O(N*P^4)
进一步思考,很容易得出满分做法。
我们发现,在一个结点上所要进行的分配人力的任务,实际是一个背包。于是在结点上做一个背包即可。
但是注意这个背包是以当前结点的所有的孩子做背包,然后因为当前节点抓捕失败后才能往孩子走,所以当前结点要枚举埋伏人数,才能得出最终的答案。
时间复杂度是O(N*P^2)
需要的知识:最短路径算法、最短路径树的概念、背包DP、树形DP
代码长度 1KB~2KB
数据和标程的下载地址: http://pan.baidu.com/share/link?shareid=3747&uk=2249476017
最后,感谢诸位的参与。感谢Vani,kAc,applepi等人的验题
PS:以上是sillycross大神的官方题解,他写的是pascal,我等c++支持者便是抓瞎,当然,我真的没看他的代码。因为看了也不懂。
以下是我自己写的c++的代码,大神不要BS我啊!
第一题:我这个蒟蒻,一看大水,果断5分钟敲完交了,没想精度问题,果断20分。。
View Code
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> using namespace std; int n,m,cnt=1,a,b,c,start,h,t,head[220],next[20020],to[20020],len[20020],s,dis[220],que[500200]; double dp[220][220],jl[220][220],f[220]; bool vis[220]; int pre[220],son[220]; void add(int v,int u,int w) { len[cnt]=w; to[cnt]=u; next[cnt]=head[v]; head[v]=cnt++; } void read() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { scanf("%d%d%d",&a,&b,&c); add(a,b,c); add(b,a,c); } scanf("%d",&s); for(int i=1;i<=n;i++) for(int j=1;j<=s;j++) scanf("%lf",&jl[i][j]); } void spfa() { start=1; memset(dis,0x3f,sizeof dis); h=1;t=2; que[1]=start; vis[start]=true; dis[start]=0; while(h<t) { int sta=que[h++]; vis[sta]=false; for(int i=head[sta];i;i=next[i]) { if(dis[to[i]]>dis[sta]+len[i]) { dis[to[i]]=dis[sta]+len[i]; pre[to[i]]=sta; if(vis[to[i]]==false) { vis[to[i]]=true; que[t++]=to[i]; } } } } } void create() { memset(head,0,sizeof head); cnt=1; for(int i=2;i<=n;i++) add(pre[i],i,1); for(int i=1;i<=n;i++) for(int j=head[i];j;j=next[j]) son[i]++; } void dfs(int u) { for(int i=1;i<=s;i++) dp[u][i]=jl[u][i]; if(head[u]==0) return; for(int i=head[u];i;i=next[i]) dfs(to[i]); for(int i=0;i<=s;i++) f[i]=0.0; for(int i=head[u];i;i=next[i]) for(int j=s;j>=0;j--) for(int k=0;k<=j;k++) f[j]=max(f[j],f[j-k]+dp[to[i]][k]); for(int i=0;i<=s;i++) f[i]=f[i]/double(son[u]); for(int i=0;i<=s;i++) for(int j=0;j+i<=s;j++) dp[u][i+j]=max(dp[u][i+j],f[j]*(1.0-jl[u][i])+jl[u][i]); } void gogo() { dfs(1); printf("%.4lf",dp[1][s]); } void go() { spfa(); create(); gogo(); } int main() { read(); go(); return 0; }
总体来说这套题的难度还是低于NOIP的,(这么低分,你也好意思说!),应该得到的教训就是,简单题只要做了就必须拿满分!还有就是,思考完善了再动手敲代码!
相关文章推荐
- 2017-07-08【NOIP提高组】模拟赛B组-连通块(connect)-题解
- 2017-07-08【NOIP提高组】模拟赛B组-山峰(summits)-题解
- 2017.10.07【NOIP提高组】模拟赛B组 偷懒的西西 题解
- 计蒜客 2017 NOIP 提高组模拟赛(一)题解
- 2017.1.15【初中部 NOIP提高组】模拟赛B组 七天使的通讯(angelus) 题解
- 2017.10.07【NOIP提高组】模拟赛B组 瑰丽华尔兹 题解
- 2017.1.15【初中部 NOIP提高组】模拟赛B组 寻找羔羊(agnus) 题解
- JZOJsenior1396.2017.04.08【NOIP提高组】模拟赛B组 T2包裹快递
- 2016.07.16【初中部 NOIP提高组 】模拟赛C
- 2017.12.09【NOIP提高组】模拟赛B组总结
- 2016.07.17【初中部 NOIP提高组 】模拟赛C
- 计蒜客 2017 NOIP 提高组模拟赛(一)Day2
- 2016.07.21【初中部 NOIP提高组 】模拟赛C
- 2016.08.11【初中部 NOIP提高组 】模拟赛C题解
- 2016.08.13【初中部 NOIP提高组 】模拟赛C
- 2016.08.13【初中部 NOIP提高组 】模拟赛C
- 2016.08.14【初中部 NOIP提高组 】模拟赛C小结
- 2016.12.03【初中部 NOIP提高C组】模拟赛
- 2017.06.05【NOIP提高组】模拟赛A组 & B组
- 2017.07.05【NOIP提高组】模拟赛A组 邮递员