您的位置:首页 > 其它

【NOIP2016】普及组魔法阵

2016-11-25 21:31 239 查看

题目描述:

六十年一次的魔法战争就要开始了,大魔法师准备从附近的魔法场中汲取魔法能量。

大魔法师有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物品的次数。

输入:



样例输入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说明:



数据规模:



分析:

如图,AB=2x,CD=x,BC>6x



我们可以把每一个物品放到一个数轴上。然后枚举x,再枚举A,就可以算出B,

但我们没法去枚举6x~n去算C和D。

我们发现可以倒过来枚举A,然后直接找最小的C,也就是A+8x+1。

那么对于每一个新的A,以前出现的C肯定都是是合法的。

于是我们用一个后缀和y去维护C*D,就可以算出ansA和ansB了。

同理算出ansC和ansD。

显然,x≤n/9。所以时间复杂度就是o(n2/9)

CODE

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,m,a[40001],w[30001],ans[4][30001];
int main()
{
int i,j,k;
freopen("magic.in","r",stdin);
freopen("magic.out","w",stdout);
scanf("%d%d",&n,&m);
for (i=1;i<=m;i++)
{
scanf("%d",&a[i]);
w[a[i]]++;
}
for (i=1;i<=n/9;i++)
{
int x=8*i+1,y=0;
for (j=n-9*i+1;j>=1;j--)
{
y+=w[j+x]*w[j+x+i];
ans[0][j]+=w[j+2*i]*y;
ans[1][j+2*i]+=w[j]*y;
}
y=0;
for (j=x+1;j<=n;j++)
{
y+=w[j-x]*w[j-x+2*i];
ans[2][j]+=w[j+i]*y;
ans[3][j+i]+=w[j]*y;
}
}
for (i=1;i<=m;i++)
printf("%d %d %d %d\n",ans[0][a[i]],ans[1][a[i]],ans[2][a[i]],ans[3][a[i]]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  NOIP