题目描述
六十年一次的魔法战争就要开始了,大魔法师准备从附近的魔法场中汲取魔法能量。
大魔法师有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的物品的魔法值。
保证1≤n≤ 15000,1≤m≤40000,1≤xi≤n。每个xi是分别在合法范围内等概率随机生成的。
输出格式
输出m行,每行四个整数。第i行的四个整数依次表示编号为i的物品作为A,B,C,D物品分别出现的次数。
保证标准输出中的每个数都不会超过10^9。每行相邻的两个数之间用恰好一个空格隔开。
输入样例
30 8
1
24
7
28
5
29
26
24
输出样例
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
题解
朴素的方法自然是枚举$a$、$b$、$c$、$d$,但是四个未知数显然不科学。所以我们要消元,用一两个未知数来表示他们之间的关系。
因为有$x_{b} - x_{a} = 2(x_{d} - x_{c})$,我们可以设$x_{d} - x_{c} = i$,则$x_{b} - x_{a} = 2i$。
又因为有$3(x_{b} - x_{a}) < x_{c} - x_{b}$,即$6i < x_{c} - x_{b}$,所以我们又设$6i + k = x_{c} - x_{b}$。
则此时我们已知方程组:
$$\left \{ \begin{matrix} x_{a} + 2i = x_{b} \\ x_{b} + 6i + k = x_{c} \\ x_{c} + i = x_{d} \end{matrix} \right.$$
所以,我们就只需要枚举$i$和$k$了。
我们设$x_{i}$的个数为$f[x_{i}]$,设$t[x_{i}][A,B,C,D]$分别表示$x_{i}$作为$A,B,C,D$物品的次数。
又设已知$a,b$时,$c,d$的个数为$sum_{1}$;已知$c,d$时,$a,b$的个数为$sum_{2}$。
易得:
$$\begin{align*} t[x_{a}][A] &= f[x_{b}] \times sum_{1} \\ t[x_{b}][B] &= f[x_{a}] \times sum_{1} \\ t[x_{c}][C] &= f[x_{d}] \times sum_{2} \\ t[x_{d}][D] &= f[x_{c}] \times sum_{2} \end{align*}$$
我们在枚举$a,b(c,d)$的时候,也不断累加$sum_{1}(sum_{2})$即可。


#include <iostream> #include <cstdio> #define MAX_N (15000 + 5) #define MAX_M (50000 + 5) using namespace std; int n, m; int x[MAX_M]; int f[MAX_N]; long long t[MAX_N][4]; int main() { scanf("%d%d", &n, &m); for(register int i = 1; i <= m; ++i) { scanf("%d", x + i); ++f[x[i]]; } int a, b, c, d; long long sum; for(register int i = 1; 9 * i + 1 < n; ++i) { a = n - 9 * i - 1; b = n - 7 * i - 1; c = n - i; d = n; sum = 0; while(a) { sum += f[c] * f[d]; t[a][0] += f[b] * sum; t[b][1] += f[a] * sum; --a; --b; --c; --d; } a = 1; b = 2 * i + 1; c = 8 * i + 2; d = 9 * i + 2; sum = 0; while(d <= n) { sum += f[a] * f[b]; t[c][2] += f[d] * sum; t[d][3] += f[c] * sum; ++a; ++b; ++c; ++d; } } for(register int i = 1; i <= m; ++i) { printf("%lld %lld %lld %lld\n", t[x[i]][0], t[x[i]][1], t[x[i]][2], t[x[i]][3]); } return 0; }