[NOIP2016 普及组] 魔法阵 - 洛谷

题意分析

给定一个四元组,四个数分别为a,b,c,d,满足以下条件:

1.a<b<c<d

2.b-a=2*(d-c)

3.b-a=(c-b)/3 //注意是实除

现在给你一个序列X,请你求出序列X中每个数分别作为a,b,c,d的个数。

算法一:暴力枚举(PTS 35)

直接进行一个暴力的打,枚举a,b,c,d,判断是否满足条件,再用四个数组分别记录个数。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
int n,m;
int maho[40010];
bool check(int a,int b,int c,int d)
{if(a>=b||b>=c||c>=d) return false;if((b-a)!=2*(d-c)) return false;if(3*(b-a)>=(c-b)) return false;return true;
}
struct node{int aa,bb,cc,dd;
}h[1000010];
int main()
{memset(h,0,sizeof(h));scanf("%d%d",&n,&m);for(int i=1;i<=m;++i){scanf("%d",&maho[i]);}for(int d=1;d<=m;++d){for(int c=1;c<=m;++c){for(int b=1;b<=m;++b){for(int a=1;a<=m;++a){if(check(maho[a],maho[b],maho[c],maho[d])) {h[a].aa++;h[b].bb++;h[c].cc++;h[d].dd++;}}}}}for(int i=1;i<=m;++i){printf("%d %d %d %d\n",h[i].aa,h[i].bb,h[i].cc,h[i].dd);}return 0;
}

时间复杂度:O(n*n*n*n)

ps:这能给35分已经算是施舍了吧。。。

算法二:暴力优化(PTS 55)

不难想到:由a<b<c<d条件可知满足条件的四元组是单调递增的,因此我们不妨现将X排序,减少循环量。(记得记录每个数在原来X序列中的位置,输出时用)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
int n,m;
struct nn{int val,pos;
}maho[40010];
bool check(int a,int b,int c,int d)
{if(a<b&&b<c&&c<d) if((b-a)==2*(d-c)) if((b-a)<(c-b)/3.0) return true;return false;
}
int h[1000010][5];
bool cmp(nn a,nn b)
{if(a.val==b.val) return a.pos < b.pos;else return a.val < b.val;
}
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=m;++i){scanf("%d",&maho[i].val);maho[i].pos=i;}sort(maho+1,maho+m+1,cmp);for(int a=1;a<=m;++a){for(int b=a+1;b<=m;++b){for(int c=b+1;c<=m;++c){for(int d=c+1;d<=m;++d){if(check(maho[a].val,maho[b].val,maho[c].val,maho[d].val)) {h[maho[a].pos][1]++;h[maho[b].pos][2]++;h[maho[c].pos][3]++;h[maho[d].pos][4]++;}}}}}for(int i=1;i<=m;++i){printf("%d %d %d %d\n",h[i][1],h[i][2],h[i][3],h[i][4]);}return 0;
}

时间复杂度:比纯暴力算法快一点,不过还是O(n*n*n*n)级别的。

ps:蒟蒻在此止步。。。。

算法三:数学计算优化(PTS 100)

毕竟给的三个条件都是一个式子,我们可以活用数学知识来将这三个式子简化。

本题简化的基本思路:用已知数表示未知数

假设t = d - c

则b - a = 2 * t

则c - b >6 * t

所以我们不妨设c - b = 6 * t + k (k > 0)

则此时可以求出:

A点到B点之间的距离为2 * t

B点到C点之间的距离为6 * t + k

C点到D点之间的距离为t

再结合条件一,我们可以得到下面一张简图。

很简陋对吧(技术力低下++)

浅显の分析

到现在大家应该都看出来了应该枚举t并用t表示数。


先弱弱地看一波数据范围。。

40000......emmmm,看来必须是O(n)的算法了呢~


枚举之前,要先算出各个变量的范围,尽量减少循环数

A的范围:

因为A最小值为1,D最大值为n,且AD=9*t+k;

则A的取值范围:[1,n-9*t-1]

D的范围:

因为AD=9*t+k,且A最小值为1,D最大值为n;

则D的取值范围:[9*t+2,n]

t的范围:

因为D最大为n,且D=A+9*t+1,A最小值为1;

则如果要是有D满足条件,则t满足9*t+2<=n,解得t<n/9;

则t的取值范围:[1,n/9)(此处避免除法,可写作t*9<n)

准备条件妥当,现在还有一个大难题摆在我们面前:如何计算答案?

再分析一下条件:在t一定,且取值范围条件均可满足时,只要满足c-b>6*t,就一定存在四元组,而且只要是满足该条件的所有a,b,c,d,均是四元组。那么若已知该状态下a,b的最大值,那么小于最大值的所有a,b均可形成一个四元组,随着t增大,a,b的最大值相应增大,这时将上个t值时四元组的个数传递下来进行处理,枚举完得到的便是答案。所以,我们可以开四个前缀和数组维护答案。


终焉の代码

分析到这里,也该谈谈代码实现了:

第一层循环:枚举t

没啥好说的。。。

第二层循环:

1.枚举a

枚举a来推b,c,d时,b在a一定的情况下相当于也是定值,那么处理的应是c,d的前缀和,因为c,d均是最大值固定,最小值移动的变量,因此c,d其实要处理的是后缀和,不过我们用倒着枚举a的方式就可以方便地处理后缀和。

for(int A=n-9*t-1;A;A--)
{int B=A+2*t;int D=A+9*t+1;int C=D-t;tem+=sum[C]*sum[D];ans[A][0]+=sum[B]*tem;ans[B][1]+=sum[A]*tem;
}

2.枚举d

与上面同理,只不过因为a,b是最小值固定,最大值移动的变量,所以是正着枚举。

for(int D=9*t+2;D<=n;++D)
{int A=D-9*t-1;int B=A+2*t;int C=D-t;tem+=sum[A]*sum[B];ans[C][2]+=sum[D]*tem;ans[D][3]+=sum[C]*tem;
}

核心代码已经展出,下面是总代码:

/* 1.x[a] < x[b] < x[c]2.x[b] - x[a] = 2 * (x[d] - x[c])3.x[b] - x[a] < (x[c] - x[b]) / 3.0Assumption: t = x[d] - x[c];then: x[b] - x[a] = 2 * t;then: x[c] - x[b] > 6 * t;Assumption: x[c] - x[b] = 6 * t + kso:A -> B: 2 * t;B -> C: 6 * t + k;C -> D: t;so:Range of t: from 1 to n / 9(unequal) Range of A: from 1 to n - 9 * t - 1;Range of D: from 9 * t + 1 + 1 to n;推出以上式子后,枚举t值,便可表示出ABCD的魔法值;再分别枚举A和D,利用乘法原理,算出每个魔法值作为ABCD的次数
*/
#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[40010];
int sum[15010];
int ans[15010][4];
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=m;++i){scanf("%d",&a[i]);sum[a[i]]++;}for(int t=1;t*9<n;++t){int tem=0;for(int D=9*t+2;D<=n;++D){int A=D-9*t-1;int B=A+2*t;int C=D-t;tem+=sum[A]*sum[B];ans[C][2]+=sum[D]*tem;ans[D][3]+=sum[C]*tem;}tem=0;for(int A=n-9*t-1;A;A--){int B=A+2*t;int D=A+9*t+1;int C=D-t;tem+=sum[C]*sum[D];ans[A][0]+=sum[B]*tem;ans[B][1]+=sum[A]*tem;}}for(int i=1;i<=m;++i){printf("%d %d %d %d\n",ans[a[i]][0],ans[a[i]][1],ans[a[i]][2],ans[a[i]][3]);}return 0;
}

时间复杂度:差不多O(n)(我真不会算)

后记:

1.帮不是很懂为什么要乘tem的童鞋解释一下: 乘法原理_百度百科

2. 如果文章中有地方与代码有出入,请以代码为准,毕竟程序一定不会骗人

[NOIP2016 普及组] 魔法阵相关推荐

  1. 【做题记录】[NOIP2016 普及组] 魔法阵

    P2119 魔法阵 2016年普及组T4 题意: 给定一系列元素 \(\{X_i\}\) ,求满足以下不等式的每一个元素作为 \(a,b,c,d\) 的出现次数 . \[\begin{cases}X_ ...

  2. noip2016普及组 魔法阵vijos2012

    描述 六十年一次的魔法战争就要开始了,大魔法师准备从附近的魔法场中汲取魔法能量. 大魔法师有m个魔法物品,编号分别为1,2,...,m.每个物品具有一个魔法值,我们用x_ix​i​​表示编号为i的物品 ...

  3. 【noip2016普及】魔法阵

    魔法阵 题目描述 六十年一次的魔法战争就要开始了,大魔法师准备从附近的魔法场中汲取魔法能量. 大魔法师有m个魔法物品,编号分别为1,2,-,m.每个物品具有一个魔法值,我们用Xi表示编号为i的物品的魔 ...

  4. NOIP2016 普及组 总结+题目吐槽+代码+简单题解

    提高组回来之后,像往年一样,做了一下普及组的题 先吐槽一下 T1 这题一眼看上去以为可以用不同种类的铅笔,没想到只能用一种种类,我240B搞定 #include<cstdio> int m ...

  5. NOIP2016普及组复赛第一题的AC程序加题解pascal

    P老师需要去商店买n支铅笔作为小朋友们参加NOIP的礼物.她发现商店一共有 3种包装的铅笔,不同包装内的铅笔数量有可能不同,价格也有可能不同.为了公平起 见,P老师决定只买同一种包装的铅笔.商店不允许 ...

  6. 洛谷——P1909 [NOIP2016 普及组] 买铅笔

    P1909 [NOIP2016 普及组] 买铅笔 题目描述 P老师需要去商店买n支铅笔作为小朋友们参加NOIP的礼物.她发现商店一共有 33种包装的铅笔,不同包装内的铅笔数量有可能不同,价格也有可能不 ...

  7. P2058 [NOIP2016 普及组] 海港

    题目背景 NOIP2016 普及组 T3 题目描述 小 K 是一个海港的海关工作人员,每天都有许多船只到达海港,船上通常有很多来自不同国家的乘客. 小 K 对这些到达海港的船只非常感兴趣,他按照时间记 ...

  8. P1909 [NOIP2016 普及组] 买铅笔

    P1909 [NOIP2016 普及组] 买铅笔 提交308.01k 通过130.89k 时间限制1.00s 内存限制125.00MB 提交答案加入题单复制题目 做题计划(首页) 个人题单 团队题单 ...

  9. [NOIP2016 普及组] 买铅笔

    [NOIP2016 普及组] 买铅笔 题目背景 NOIP2016 普及组 T1 题目描述 P 老师需要去商店买 nnn 支铅笔作为小朋友们参加 NOIP 的礼物.她发现商店一共有 333 种包装的铅笔 ...

  10. NOIP2016 普及组第四题 魔法阵magic 题解

    题目描述 六十年一次的魔法战争就要开始了,大魔法师准备从附近的魔法场中汲取魔法能量. 大魔法师有m个魔法物品,编号分别为1,2,-,m.每个物品具有一个魔法值,我们用Xi表示编号为i的物品的魔法值.每 ...

最新文章

  1. linux下热插拔事件的产生是怎样通知到用户空间,kobject_uevent_env之uevent【转】...
  2. sql server 2000 数据库。 怎样用sql语句,在没有主键的情况下删除数据库中多条......
  3. 怎么讲服务器上的文件装进电脑,怎么把电脑文件放进云服务器
  4. 一维有限元法matlab,有限元matlab研究.ppt
  5. 【Tensorflow】更新后报错 numpy.core.umath
  6. redis密码设置、访问权限控制等安全设置
  7. 基于ROS的运动识别
  8. Eclipse探秘-第一章-Eclipse启动(1)
  9. 如何优化cocos2d的使用内存
  10. 机器视觉:线阵相机知识汇总
  11. 【Homography Estimation】《Deep Image Homography Estimation》
  12. 段地址x16+偏移地址=物理地址的本质含义
  13. 计算机office安装错误代码,office安装过程中错误提示1402解决方法
  14. 阿里云服务器学生免费领取指南
  15. 英文标题中哪些词不用大写
  16. 对于软件,我是认真的
  17. 关于“微信公众平台测试号管理接口配置信息配置失败”的问题解决办法
  18. (转载)UIKIt力学教程
  19. 黑马Redis学习——实战篇(4)
  20. linux心跳包检测代码_Socket心跳包机制

热门文章

  1. linux 查看硬盘健康,linux硬盘检测健康状态
  2. Android-MeasureSpec那些事 1
  3. java fastfds操作文件
  4. 资源下载网站整站资源|建站6万资源数据32G整站下载
  5. LoadRunner教程(29)-LoadRunner监控Tomcat
  6. 组态软件及其应用方式
  7. 华为网络配置(ACL)
  8. 一起来学FPGA(vhdl)三:分频器实验
  9. 【20保研】四川大学网络空间安全学院2019年优秀大学生暑期夏令营招生简章
  10. 计算机硬件报警声音,电脑开机报警声音大全详解及处理