咱们讲一个悲伤的故事。c++
从前有一个贫穷的樵夫在河边砍柴。函数
这时候河里出现了一个水神,夺过了他的斧头,说:spa
“这把斧头,是否是你的?”code
樵夫一看:“是啊是啊!”orm
水神把斧头扔在一边,又拿起一个东西问:ip
“这把斧头,是否是你的?”input
樵夫看不清楚,但又怕真的是本身的斧头,只好又答:“是啊是啊!”it
水神又把手上的东西扔在一边,拿起第三个东西问:io
“这把斧头,是否是你的?”form
樵夫仍是看不清楚,可是他以为再这样下去他就无法砍柴了。
因而他又一次答:“是啊是啊!真的是!”
水神看着他,哈哈大笑道:
“你看看你如今的样子,真是丑陋!”
以后就消失了。
樵夫以为很坑爹,他今天不只没有砍到柴,还丢了一把斧头给那个水神。
因而他准备回家换一把斧头。
回家以后他才发现真正坑爹的事情才刚开始。
水神拿着的的确是他的斧头。
可是不必定是他拿出去的那把,还有多是水神不知道怎么偷偷从他家里拿走的。
换句话说,水神可能拿走了他的一把,两把或者三把斧头。
樵夫以为今天真是倒霉透了,但无论怎么样日子还得过。
他想统计他的损失。
樵夫的每一把斧头都有一个价值,不一样斧头的价值不一样。总损失就是丢掉的斧头价值和。
他想对于每一个可能的总损失,计算有几种可能的方案。
注意:若是水神拿走了两把斧头a和b,(a,b)和(b,a)视为一种方案。拿走三把斧头时,(a,b,c),(b,c,a),(c,a,b),(c,b,a),(b,a,c),(a,c,b)视为一种方案。
第一行是整数N,表示有N把斧头。
接下来n行升序输入N个数字Ai,表示每把斧头的价值。
若干行,按升序对于全部可能的总损失输出一行x y,x为损失值,y为方案数
4
4
5
6
7
4 1
5 1
6 1
7 1
9 1
10 1
11 2
12 1
13 1
15 1
16 1
17 1
18 1
样例解释
11有两种方案是4+7和5+6,其余损失值都有惟一方案,例如4=4,5=5,10=4+6,18=5+6+7.
全部数据知足:Ai<=40000
考虑一个两个三个分别的生成函数
容斥掉不合法贡献
#include<bits/stdc++.h> using namespace std; const int N = 3e5 + 10; const double eps = 1e-6; const double PI = acos(-1); typedef complex<double> Complex; Complex f[N], g[N], h[N], p[N], q[N], w[N][2]; void init() { for (int i = 1; i < (1 << 18); i <<= 1) { w[i][0] = w[i][1] = Complex(1, 0); Complex wn(cos(PI / i), sin(PI / i)); for (int j = 1; j < i; j++) w[i + j][1] = w[i + j - 1][1] * wn; wn = Complex(cos(PI / i), -sin(PI / i)); for (int j = 1; j < i; j++) w[i + j][0] = w[i + j - 1][0] * wn; } } void transform(Complex t[N], int len, int typ) { for (int i = 0, j = 0, k; j < len; j++) { if (i > j) swap(t[i], t[j]); for (k = (len >> 1); k & i; k >>= 1) i ^= k; i ^= k; } for (int i = 1; i < len; i <<= 1) { for (int j = 0; j < len; j += (i << 1)) { for (int k = 0; k < i; k++) { Complex x = t[j + k], y = t[j + k + i] * w[i + k][typ]; t[j + k] = x + y; t[j + k + i] = x - y; } } } if (typ) return; for (int i = 0; i < len; i++) t[i] = Complex(t[i].real() / (double) len, t[i].imag()); } int n, a[N]; int main() { #ifdef dream_maker freopen("input.txt", "r", stdin); #endif init(); int maxval = 0; scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); maxval = max(maxval, a[i]); } maxval = maxval * 3 + 1; for (int i = 1; i <= n; i++) { f[a[i]] = Complex(f[a[i]].real() + 1, f[a[i]].imag()); p[a[i] * 2] = Complex(p[a[i] * 2].real() + 1, p[a[i] * 2].imag()); q[a[i] * 3] = Complex(q[a[i] * 3].real() + 1, q[a[i] * 3].imag()); } int len = 1 << (int) ceil(log2(maxval * 2 - 1)); transform(f, len, 1); for (int i = 0; i < len; i++) g[i] = f[i] * f[i]; transform(g, len, 0); for (int i = 0; i < len; i++) g[i] -= p[i]; transform(g, len, 1); for (int i = 0; i < len; i++) h[i] = f[i] * f[i] * f[i]; transform(h, len, 0); transform(p, len, 1); for (int i = 0; i < len; i++) p[i] = f[i] * p[i]; transform(g, len, 0); transform(f, len, 0); transform(p, len, 0); for (int i = 0; i <= len; i++) { h[i] -= p[i] + p[i] + p[i]; h[i] += q[i] + q[i]; } for (int i = 0; i <= maxval; i++) if ((int) (round(f[i].real()) + round(g[i].real()) / 2 + round(h[i].real()) / 6)) printf("%d %d\n", i, (int) (round(f[i].real()) + round(g[i].real()) / 2 + round(h[i].real()) / 6)); return 0; }