【NOIP普及组2016】&魔法阵 This is magic!&
来源:互联网 发布:天龙八部九阴神爪 知 编辑:程序博客网 时间:2024/06/13 23:46
2016压轴题-魔法阵
- 2016压轴题-魔法阵
- 前言
- 题目描述
- 题目分析-暴力枚举Om4
- 开始优化-桶思想优化On3
- 高端操作-学不来的数学分析On2
- END
前言
听闻老前辈们道这道题好像很难的样子,于是我就去做了……
然后我就TLE了
于是偷偷瞟了一眼大老前辈们的博客,发现这道题好像,还是枚举,只是有用到【数学方法】优化罢了
完了完了,一提到数学,我脑子里顿时腾起了层层云雾,所以最后决定还是来写写东西。
来吧,欢迎进入MAGIC的世界
题目描述
六十年一次的魔法战争就要开始了,大魔法师准备从附近的魔法场中汲取魔法能量。
大魔法师有m个魔法物品,编号分别为
大魔法师认为,当且仅当四个编号为
现在,大魔法师想要知道,对于每个魔法物品,作为某个魔法阵的A物品出现的次数,作为B物品的次数,作为C物品的次数,和作为D物品的次数。
输入
输入文件的第一行包含两个空格隔开的正整数n和m。
接下来m行,每行一个正整数,第i+1行的正整数表示Xi,即编号为i的物品的魔法值。
保证
输出
共输出m行,每行四个整数。第i行的四个整数依次表示编号为i的物品作 为A,B,C,D物品分别出现的次数。
保证标准输出中的每个数都不会超过10^9。
每行相邻的两个数之间用恰好一个空格隔开。
样例输入
输入样例#1:
30 8
1
24
7
28
5
29
26
24
输入样例#2:
15 15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
样例输出
输出样例#1:
4 0 0 0
0 0 1 0
0 2 0 0
0 0 1 1
1 3 0 0
0 0 0 2
0 0 2 2
0 0 1 0
输出样例#2:
5 0 0 0
4 0 0 0
3 5 0 0
2 4 0 0
1 3 0 0
0 2 0 0
0 1 0 0
0 0 0 0
0 0 0 0
0 0 1 0
0 0 2 1
0 0 3 2
0 0 4 3
0 0 5 4
0 0 0 5
样例说明
样例#1:
共有5个魔法阵,分别为:
物品1,3,7,6,其魔法值分别为1,7,26,29;
物品1,5,2,7,其魔法值分别为1,5,24,26;
物品1,5,7,4,其魔法值分别为1,5,26,28;
物品1,5,8,7,其魔法值分别为1,5,24,26;
物品5,3,4,6,其魔法值分别为5,7,28,29。
以物品5为例,它作为A物品出现了1次,作为B物品出现了3次,没有作为C物品或者D物品出现,所以这一行输出的四个数依次为1,3,0,0。
此外,如果我们将输出看作一个m行4列的矩阵,那么每一列上的m个数之和都应等于魔法阵的总数。所以,如果你的输出不满足这个性质,那么这个输出一定不正确。你可以通过这个性质在一定程度上检查你的输出的正确性。
题目分析-暴力枚举O(m^4)
“这么简单,当然是暴力啦~”
于是一段清晰的思路像一片Sunshine:分别枚举
条件反射地想到,可以剪枝!在找
然后写出来以后,突然瞟了一眼数据范围……
真是莫名其妙。
一段十分失败的枚举代码:
#include<cstdio>int X[40005];int ansA[40005],ansB[40005],ansC[40005],ansD[40005];int main(){ int n,m; scanf("%d %d",&n,&m); for(int i=1;i<=m;i++) scanf("%d",&X[i]); for(int A=1;A<=m;A++) { for(int B=1;B<=m;B++) { if( X[A] >= X[B] ) continue; for(int C=1;C<=m;C++) { if( X[B] >= X[C] ) continue; if( 3 * (X[B] - X[A]) >= X[C] - X[B] ) continue; for(int D=1;D<=m;D++) { if( X[C] >= X[D] ) continue; if( X[B] - X[A] != 2*(X[D] - X[C]) ) continue; ansA[A]++;ansB[B]++;ansC[C]++;ansD[D]++; } } } } for(int i=1;i<=m;i++) printf("%d %d %d %d\n",ansA[i],ansB[i],ansC[i],ansD[i]);}//期望35%-实得55%
开始优化-桶思想优化O(n^3)
再次扫一眼题目,我们发现n的范围要远远小于m的范围,也就是说有大部分的数据魔法值其实是相同的。从m出发的话,给你
于是我们便想到,如果“从n入手”行不行?
不妨按照魔法值来存储对应魔法值的物品数量,计算方案数时采用乘法原理,输出时访问魔法值对应的值。一段稍带迷雾的代码在我眼前渐渐浮现。再计算一下时间复杂度:
还能优化吗?可以。当我们确定A、B、C时,实际上根据
感觉考试的时候只能够撑到这里了,再深层次的话……【吐血】
得到差不多一般般的代码
#include<cstdio>int X[40005];int K[15005];int ansA[15005],ansB[15005],ansC[15005],ansD[15005];int main(){ int n,m; scanf("%d %d",&n,&m); for(int i=1;i<=m;i++) { scanf("%d",&X[i]); K[X[i]]++; } for(int A=1;A<=n;A++) { if( K[A] == 0 ) continue; for(int B=A+1;B<=n;B++) { if( K[B] == 0 ) continue; if( ( B - A ) % 2 == 1 ) continue; for(int C=(B-A)*3+B+1;C<=n;C++) { if( K[C] == 0 ) continue; int D = C + ( B - A ) / 2; if( D > n ) continue; if( K[D] == 0 ) continue; ansA[A]+=(K[B]*K[C]*K[D]); ansB[B]+=(K[A]*K[C]*K[D]); ansC[C]+=(K[A]*K[B]*K[D]); ansD[D]+=(K[A]*K[B]*K[C]); } } } for(int i=1;i<=m;i++) printf("%d %d %d %d\n",ansA[X[i]],ansB[X[i]],ansC[X[i]],ansD[X[i]]);}//期望80%-实得85%
高端操作-学不来的数学分析O(n^2)
先放代码镇镇大佬们的英魂。
#include<cstdio>#include<cstring>int X[16000],a[40005],S[16000];int A[40005],B[40005],C[40005],D[40005];int main(){ int n,m; scanf("%d %d",&n,&m); for(int i=1;i<=m;i++) { scanf("%d",&a[i]); X[a[i]]++; } for(int i=1;i*9<n;i++) { memset(S,0,sizeof(S)); for(int j=2*i+1;j<=n-7*i-1;j++) S[j] = X[j - 2*i] * X[j]; for(int j=1;j<=n;j++) S[j] += S[j-1]; for(int j=9*i+1;j<=n;j++) D[j] += S[j - 7*i - 1] * X[j - i]; for(int j=7*i+1;j<=n-i;j++) C[j] += S[j - 6*i -1] * X[j + i]; memset(S,0,sizeof(S)); for(int j=9*i+1;j<=n;j++) S[j] = X[j - i] * X[j]; for(int j=n;j>=1;j--) S[j] += S[j+1]; for(int j=2*i+1;j<=n-7*i-1;j++) B[j] += S[j + 7*i + 1] * X[j - 2*i]; for(int j=1;j<=n-9*i-1;j++) A[j] += S[j + 9*i +1] * X[j + 2*i]; } for(int i = 1;i<=m;i++) printf("%d %d %d %d\n",A[a[i]],B[a[i]],C[a[i]],D[a[i]]);}//期望100%
再发一张大佬用的分析图
恩,我们所知道的条件已经全部标在图上了
啥你看不懂?那我稍微解释解释:
图中的直线【你要相信我这真的不是线段】叫做数轴【对不起我以为你不知道】,轴上的点
感觉卡住了……怎么办?
还是从时间复杂度的角度入手吧:
压到
压到
看来只能压到
我们如果确定了
反过来,如果我们确定了在某个范围内的
好像有点希望了?!
令
可以得到确定
同理,也可在
woc这么高大上的吗!
果然NOIP普及压轴题都是思维复杂,挑战脑力,代码极其* *的题吗!
END
THANKS FOR READING THERE!
就是这样,新的一天里,也请多多关照哦(ノω<。)ノ))☆.。~
- 【NOIP普及组2016】&魔法阵 This is magic!&
- 【noip普及组2016】第四题“魔法阵”
- NOIP2016 普及组第四题 魔法阵magic 题解
- noip2016普及组T4 魔法阵(magic)(错误)
- NOIP【2016普及组】 考后有感(买铅笔,回文日期,海港,魔法阵)
- 【NOIP2016】普及组魔法阵
- 【原创】【NOIP2016普及组】魔法阵
- 【NOIP2016普及组复赛】魔法阵
- 【NOIP2016普及组复赛】魔法阵
- NOIP2016普及组[魔法阵]题解
- 2105. 【NOIP2016普及组复赛】魔法阵
- [NOIP2016普及] 魔法阵
- 【noip2016普及】魔法阵
- 2016noip普及组初赛答案
- noip普及组2016测试总结
- 【noip普及组2016】第三题“海港”
- NOIP-2016-普及组 复赛题解
- [NHZXOI2017]2016NOIP普及组复赛题解
- windows 下xdebug 安装和使用
- appium-连接真机
- 三子棋
- 在C#中,Json的序列化和反序列化的几种方式总结
- ant删除文件操作
- 【NOIP普及组2016】&魔法阵 This is magic!&
- springMVC之mvc:interceptors拦截器的用法
- 学习心得
- selenium开发环境部署Maven官方依赖porm文件分享
- 编码与Python逻辑运算
- Lucene.NET使用入门(二)【简单的搜索网站示例】
- vue中的所有axios请求都会发送2次,但是第一次不返回数据的原因
- RabbitMQ消息队列(一): Detailed Introduction 详细介绍
- 学习心得