NOIP2016 普及组第四题 魔法阵magic 题解
2016-11-28 19:45
281 查看
题目描述
六十年一次的魔法战争就要开始了,大魔法师准备从附近的魔法场中汲取魔法能量。大魔法师有m个魔法物品,编号分别为1,2,…,m。每个物品具有一个魔法值,我们用Xi表示编号为i的物品的魔法值。每个魔法值Xi是不超过n的正整数,可能有多个物品的魔法值相同。
大魔法师认为,当且仅当四个编号为a,b,c,d的魔法物品满足xa<xb<xc<xd,xb−xa=2(xd−xc),并且xb−xa<(xc−xb)/3时,这四个魔法物品形成了一个魔法阵,他称这四个魔法物品分别为这个魔法阵的A物品,B物品,C物品,D物品。
现在,大魔法师想要知道,对于每个魔法物品,作为某个魔法阵的A物品出现的次数,作为B物品的次数,作为C物品的次数,和作为D物品的次数。
输入输出格式
输入格式:输入文件的第一行包含两个空格隔开的正整数n和m。
接下来m行,每行一个正整数,第i+1行的正整数表示Xi,即编号为i的物品的魔法值。
保证每个Xi是分别在合法范围内等概率随机生成的。
输出格式:
共输出m行,每行四个整数。第i行的四个整数依次表示编号为i的物品作 为A,B,C,D物品分别出现的次数。
保证标准输出中的每个数都不会超过10^9。
每行相邻的两个数之间用恰好一个空格隔开。
输入输出样例
输入样例#1:30 8
1
24
7
28
5
29
26
24
输出样例#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:
15 15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
输出样例#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
题解
对于一道普及组的题目来说,这道题的难度还是有点大的首先要读懂题,题目中有大写X和小写x,(在上面我已经改了),其实是一样的,可能会有人因此混淆
列出条件
1.xa<xb<xc<xd
2.xb−xa=2(xd−xc)
3.xb−xa<(xc−xb)/3
先考虑稍微暴力点的方法
对于第一个条件,直接将所有东西存进一个桶里,桶的大小不会超过N(15000),每次不是枚举第几个魔法值,而是枚举魔法值
第二个条件的意思是后前两个数的差等于后两个数的差的两倍
可以利用条件三加一个小优化,这样在统计答案的时候也就不用判断是否满足条件三了
设后两个数的差为j
xb−xa<(xc−xb)/3
2∗j<(xc−xb)/3
6∗j<xc−xb
xc>xb+6∗j
这样,在枚举xc的时候就从6∗j+xb+1开始枚举就行了
那么就可以考虑枚举后两个数的差,可以算出前两个数的差,再枚举xa算出xb,枚举xc算出xd然后统计答案
如何统计答案?
详细来说,设t[x]表示x这个值有多少个,设ans[x][1 4]表示x这个数作为第一个道第四个数出现了几次,那么
ans[xa][1]=t[xb]∗t[xc]∗t[xd]
ans[xb][2]=t[xa]∗t[xc]∗t[xd]
ans[xc][3]=t[xa]∗t[xb]∗t[xd]
ans[xd][4]=t[xb]∗t[xc]∗t[xd]
输出时对于每个输入的魔法值x,输出ans[x][1],ans[x][2],ans[x][3],ans[x][4]
预计得分:60~85
考虑优化
同样先枚举后两个数的差j
那么对于xa=0的时候,另外三个数的最小值为:
xb=2∗j
xc=8∗j+1
xc=9∗j+1
是根据三个条件得出的
每次只需枚举xa,算答案的时候对于前两个数直接加上后两个数所有的可能情况之和,对于后两个数直接加上前两个数所有可能的情况之和
如何求呢?
用sum1记录从最小的xa(值为1)到当前的xa和所对应的xb的∑t[xa]∗t[xb]
即sum1=∑t[xa]∗t[xb]
类似,用sum2记录xd从当前xa可能的最小值(xd=xa+9*j+1)到最大xd(xd=n)和所对应xc的∑t[xc]∗t[xd]
即sum2=∑t[xc]∗t[xd]
那么
ans[xa][1]=t[xb]∗sum2
ans[xb][2]=t[xa]∗sum2
ans[xc][3]=t[xd]∗sum1
ans[xd][4]=t[xc]∗sum1
不理解的话可以在我的代码中看一看
代码
#include<cstdio> #include<cstring> #include<algorithm> #define fo(i,a,b) for(int i=a;i<=b;i++) #define N 41000 using namespace std; int n,m,e ,t ,ans [4]; void read(int &x) { char c;c=getchar();int n=0; for(;c<'0'||c>'9';c=getchar()); for(;c>='0'&&c<='9';c=getchar()) n=n*10+c-48; x=n; } int main() { freopen("magic.in","r",stdin);freopen("magic.out","w",stdout); read(n);read(m); fo(i,1,m) read(e[i]),t[e[i]]++; int b,c,d; fo(j,1,2000) { b=2*j;c=8*j+1;d=c+j; int sum=0,sum2=0; fo(i,d+1,n) sum+=t[i]*t[i-j]; fo(a,1,n) { b++;c++;d++; sum2+=t[a]*t[b]; if(d>n) break; if(t[a]*t[b]>0) { ans[a][0]+=t[b]*sum; ans[b][1]+=t[a]*sum; } if(t[c]*t[d]>0) { ans[c][2]+=t[d]*sum2; ans[d][3]+=t[c]*sum2; } sum-=t[d]*t[c]; } } fo(i,1,m) printf("%d %d %d %d\n",ans[e[i]][0],ans[e[i]][1],ans[e[i]][2],ans[e[i]][3]); }
相关文章推荐
- NOIP2016普及组第四题——魔法阵
- 【NOIP普及组2016】&魔法阵 This is magic!&
- NOIP2016普及组第四题魔法阵解说+水法
- NOIP2016普及组 第四题 题解
- NOIP2016普及组第四题——魔法阵
- noip2016普及组T4 魔法阵(magic)(错误)
- noip2016普及组复赛第四题 T4魔法阵
- NOIP2016普及组第四题——魔法阵
- ◆竞赛题目◆◇NOIP2016普及组◇ 魔法阵
- magic(NOIP2016普及组复赛)
- noip2016普及组 题解
- 【NOIP2016普及组】解题报告 买铅笔 回文日期 海港 魔法阵
- 【NOIP2016】普及组魔法阵
- NOIP-2016-普及-题解
- 【NOIP2016普及组复赛】魔法阵
- NOIP2016普及组复赛第一题的ACC程序加题解pascal
- noip2016普及组题解和心得
- 【原创】【NOIP2016普及组】魔法阵
- NOIP-2016-普及组 复赛题解
- 【NOIP2016普及组复赛】魔法阵