六十年一次的魔法战争就要开始了,大魔法师准备从附近的魔法场中汲取魔法能量。
大魔法师有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
#include
#include
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 41000
using namespace std;
int n,m,e[N],t[N],ans[N][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]);
}