bzoj3771 Triple

题目链接

bzoj3771 Triple
粘一下题面吧还是qwqqqqq,挺好玩的
我们讲一个悲伤的故事。
从前有一个贫穷的樵夫在河边砍柴。
这时候河里出现了一个水神,夺过了他的斧头,说:
“这把斧头,是不是你的?”
樵夫一看:“是啊是啊!”
水神把斧头扔在一边,又拿起一个东西问:
“这把斧头,是不是你的?”
樵夫看不清楚,但又怕真的是自己的斧头,只好又答:“是啊是啊!”
水神又把手上的东西扔在一边,拿起第三个东西问:
“这把斧头,是不是你的?”
樵夫还是看不清楚,但是他觉得再这样下去他就没法砍柴了。
于是他又一次答:“是啊是啊!真的是!”
水神看着他,哈哈大笑道:
“你看看你现在的样子,真是丑陋!”
之后就消失了。
樵夫觉得很坑爹,他今天不仅没有砍到柴,还丢了一把斧头给那个水神。
于是他准备回家换一把斧头。
回家之后他才发现真正坑爹的事情才刚开始。
水神拿着的的确是他的斧头。
但是不一定是他拿出去的那把,还有可能是水神不知道怎么偷偷从他家里拿走的。
换句话说,水神可能拿走了他的一把,两把或者三把斧头。
樵夫觉得今天真是倒霉透了,但不管怎么样日子还得过。
他想统计他的损失。
樵夫的每一把斧头都有一个价值,不同斧头的价值不同。总损失就是丢掉的斧头价值和。
他想对于每个可能的总损失,计算有几种可能的方案。
注意:如果水神拿走了两把斧头a和b,(a,b)和(b,a)视为一种方案。拿走三把斧头时,(a,b,c),(b,c,a),(c,a,b),(c,b,a),(b,a,c),(a,c,b)视为一种方案。

题解

所谓形式幂级数,字面意思理解嘛
构造生成函数A\(\{0,x^{w_1},...x^{w_2},...x^{w_n}\}\) 幂为价值,洗漱为方案数
那么 , \(A^2\) 便是两两组合两种的情况,\(A^3\)便是三三
题目要求无顺序,每一种情况除一个阶乘,然后发现有重复取得情况如\(\{xx\}\{xxy\}\)
构造一个某把斧头钦定选两次的生成函数B:\(\{0,x^{2w_1},...x^{2w_2},...x^{2w_n}\}\)
三次的C:\(\{0,x^{3w_1},...x^{3w_2},...x^{3w_n}\}\)
对于两斧组合,同一个被选了两次,直接减去B
那么A*B便是包含两个重复斧头的三斧方案,这种组合有3种排列方式\(\{xyx\}\{xxy\}\{yxx\}\)所以需要减去\(3*A*B\)\(\{xxx\}\)只有一种,多减了两次,便再\(+2*C\)
fft优化一下

代码

#include<cmath> 
#include<cstdio>
#include<cstring> 
#include<algorithm> 

inline int read() { 
	int x = 0; 
	char c = getchar(); 
	while(c < '0' || c > '9') c = getchar(); 
	while(c <= '9' && c >= '0')x = x * 10 + c- '0',c = getchar(); 
	return x ; 
} 
#define pi acos(-1.0) 
struct Complex {
	double x,y; 
	Complex(double a = 0,double b = 0) : x(a),y(b)	{}; 
} ;
Complex operator + (Complex a,Complex b) { return Complex(a.x + b.x,a.y + b.y);} 
Complex operator - (Complex a,Complex b) { return Complex(a.x - b.x,a.y - b.y);} 
Complex operator * (Complex a,Complex b) { return Complex(a.x * b.x - a.y * b.y,a.x * b.y + a.y * b.x);} 

const int maxn = 1000007; 
int n;
Complex A[maxn],B[maxn],C[maxn];  
void fft(Complex *a,int n,int type) { 
	for(int i = 0,j = 0;i < n;++ i) { 
		if(i < j) std::swap(a[i],a[j]); 
		for(int k = n >> 1;(j ^= k) < k;k >>= 1);
	} 
	for(int m = 2;m <= n;m <<= 1) { 
		Complex w1 = Complex (cos(2 * pi / m),type * sin(2 * pi / m)); 
		for(int i = 0;i < n;i += m) { 
			Complex w = Complex(1,0); 
			for(int k = 0;k < (m >> 1);++ k) {
				Complex t = w * a[i + k + (m >> 1)],u = a[i + k]; 
				a[i + k] = u + t; 
				a[i + k + (m >> 1)] = u - t; 
				w = w  * w1; 
			} 
		} 
	} 
} 
Complex ans[maxn]; 
int main() { 
	n = read(); int lim = 0; 
	for(int tmp,i = 1;i <= n;++ i) { 
		tmp = read(); 
		A[tmp] = Complex(1,0); 
		B[tmp * 2] = Complex(1,0); 
		C[tmp * 3] = Complex(1,0); 
		lim = std::max(lim,tmp * 3); 
	} 
	for(n = 1;n <= lim;n <<= 1); 
	fft(A,n,1); 
       	fft(B,n,1); 
	fft(C,n,1); 
	for(int i = 0;i < n;++ i) 
		ans[i] = A[i] + (A[i] * A[i] - B[i]) * Complex(1.0 / 2.0,0) + (A[i] * A[i] * A[i] - A[i] * B[i] * Complex(3.0,0) + Complex(2.0,0) * C[i]) * Complex(1.0 / 6.0,0); 
	fft(ans,n,-1); 
	for(int i = 0;i < n;++ i) { 
		int T = ans[i].x / n + 0.5; 
		if(T) printf("%d %d\n",i,T); 
	} 	
	return 0; 
} 	

posted @ 2018-06-13 14:50  zzzzx  阅读(95)  评论(0编辑  收藏  举报