bzoj3771 Triple

3771: Triple

Time Limit: 20 Sec  Memory Limit: 64 MB

Submit: 313  Solved: 174

[Submit][Status][Discuss]

Description

我们讲一个悲伤的故事。

从前有一个贫穷的樵夫在河边砍柴。

这时候河里出现了一个水神,夺过了他的斧头,说:

“这把斧头,是不是你的?”

樵夫一看:“是啊是啊!”

水神把斧头扔在一边,又拿起一个东西问:

“这把斧头,是不是你的?”

樵夫看不清楚,但又怕真的是自己的斧头,只好又答:“是啊是啊!”

水神又把手上的东西扔在一边,拿起第三个东西问:

“这把斧头,是不是你的?”

樵夫还是看不清楚,但是他觉得再这样下去他就没法砍柴了。

于是他又一次答:“是啊是啊!真的是!”

水神看着他,哈哈大笑道:

“你看看你现在的样子,真是丑陋!”

之后就消失了。

樵夫觉得很坑爹,他今天不仅没有砍到柴,还丢了一把斧头给那个水神。

于是他准备回家换一把斧头。

回家之后他才发现真正坑爹的事情才刚开始。

水神拿着的的确是他的斧头。

但是不一定是他拿出去的那把,还有可能是水神不知道怎么偷偷从他家里拿走的。

换句话说,水神可能拿走了他的一把,两把或者三把斧头。

樵夫觉得今天真是倒霉透了,但不管怎么样日子还得过。

他想统计他的损失。

樵夫的每一把斧头都有一个价值,不同斧头的价值不同。总损失就是丢掉的斧头价值和。

他想对于每个可能的总损失,计算有几种可能的方案。

注意:如果水神拿走了两把斧头a和b,(a,b)和(b,a)视为一种方案。拿走三把斧头时,(a,b,c),(b,c,a),(c,a,b),(c,b,a),(b,a,c),(a,c,b)视为一种方案。

Input

第一行是整数N,表示有N把斧头。

接下来n行升序输入N个数字Ai,表示每把斧头的价值。

Output

若干行,按升序对于所有可能的总损失输出一行x y,x为损失值,y为方案数。

Sample Input

4

4

5

6

7

Sample Output

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.

HINT

所有数据满足:Ai<=40000

FFT+容斥原理

听说这个叫母函数?

这里要考虑重复问题,所以要用容斥。

多项式A,对于每一项x,如果存在一个物品的价值v满足x=v,则第x项为1,否则为0。

多项式B,对于每一项x,如果存在一个物品的价值v满足x=2v,则第x项为1,否则为0。

多项式C,对于每一项x,如果存在一个物品的价值v满足x=3v,则第x项为1,否则为0。

然后根据容斥,一个物品方案数是A,两个物品方案数是(A^2-B)/2,三个物品方案数是(A^3-3*A*B+2*C)/6。

所以最终答案ans=A+(A^2-B)/2+(A^3-3*A*B+2*C)/6。

多项式的乘法用FFT做,时间复杂度O(n*logn)。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define maxn 150000
using namespace std;
int n,m,rev[maxn];
const double pi=acos(-1.0);
struct CP
{
	double x,y;
	CP(double xx=0,double yy=0){x=xx;y=yy;}
	friend CP operator +(CP a,CP b){return CP(a.x+b.x,a.y+b.y);}
	friend CP operator -(CP a,CP b){return CP(a.x-b.x,a.y-b.y);}
	friend CP operator *(CP a,CP b){return CP(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
	friend CP operator *(CP a,double k){return CP(a.x*k,a.y*k);}
	friend CP operator /(CP a,double k){return CP(a.x/k,a.y/k);}
}a[maxn],b[maxn],c[maxn],ans[maxn];
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
void FFT(CP *a,int n,int flag)
{
	F(i,0,n-1) if (rev[i]>i) swap(a[i],a[rev[i]]);
	for(int m=2;m<=n;m<<=1)
	{
		int mid=m>>1;
		CP wn(cos(2.0*pi*flag/m),sin(2.0*pi*flag/m));
		for(int i=0;i<n;i+=m)
		{
			CP w(1.0,0);
			F(j,i,i+mid-1)
			{
				CP u=a[j],v=a[j+mid]*w;
				a[j]=u+v;a[j+mid]=u-v;
				w=w*wn;
			}
		}
	}
	if (flag==-1) F(i,0,n-1) a[i].x/=n;
}
int main()
{
	m=131072;
	F(i,1,m-1) rev[i]=(rev[i>>1]>>1)+((i&1)<<16);
	n=read();
	F(i,1,n){int x=read();a[x]=CP(1.0,0);b[x*2]=CP(1.0,0);c[x*3]=CP(1.0,0);}
	FFT(a,m,1);FFT(b,m,1);FFT(c,m,1);
	F(i,0,m-1) ans[i]=a[i]+(a[i]*a[i]-b[i])/2.0+(a[i]*a[i]*a[i]-a[i]*b[i]*3.0+c[i]*2.0)/6.0;//重点理解这个式子
	FFT(ans,m,-1);
	F(i,0,m-1)
	{
		int x=round(ans[i].x);
		if (x>0) printf("%d %d\n",i,x);
	}
	return 0;
}
时间: 2024-10-21 16:33:57

bzoj3771 Triple的相关文章

【BZOJ3771】Triple 生成函数+FFT

[BZOJ3771]Triple Description 我们讲一个悲伤的故事. 从前有一个贫穷的樵夫在河边砍柴. 这时候河里出现了一个水神,夺过了他的斧头,说: “这把斧头,是不是你的?” 樵夫一看:“是啊是啊!” 水神把斧头扔在一边,又拿起一个东西问: “这把斧头,是不是你的?” 樵夫看不清楚,但又怕真的是自己的斧头,只好又答:“是啊是啊!” 水神又把手上的东西扔在一边,拿起第三个东西问: “这把斧头,是不是你的?” 樵夫还是看不清楚,但是他觉得再这样下去他就没法砍柴了. 于是他又一次答:“

【bzoj3771】Triple FFT+容斥原理

题目描述 樵夫的每一把斧头都有一个价值,不同斧头的价值不同.总损失就是丢掉的斧头价值和. 他想对于每个可能的总损失,计算有几种可能的方案. 注意:如果水神拿走了两把斧头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为损失值,

PAT 1009. Triple Inversions (35) 数状数组

Given a list of N integers A1, A2, A3,...AN, there's a famous problem to count the number of inversions in it. An inversion is defined as a pair of indices i < j such that Ai > Aj. Now we have a new challenging problem. You are supposed to count the

hdu 5517 Triple(二维树状数组)

题目链接:hdu 5517 Triple 题意: 有n个两元组A,有m个三元组B,然后set C有一个计算方式. 现在让你找set TOP的size. 题解: 理解题意后,显然对于每个b的分组,只有最大的a才有贡献, 然后就可以发现set B中每个元素按照e分组后,只会对应一个a,所以最多有1e5个三元组可能有贡献. 然后将这个三元组排一下序,用二维树状数组搞搞就行了. 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=(a);i&l

【BZOJ 3771】 3771: Triple (FFT+容斥)

3771: Triple Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 547  Solved: 307 Description 我们讲一个悲伤的故事. 从前有一个贫穷的樵夫在河边砍柴. 这时候河里出现了一个水神,夺过了他的斧头,说: "这把斧头,是不是你的?" 樵夫一看:"是啊是啊!" 水神把斧头扔在一边,又拿起一个东西问: "这把斧头,是不是你的?" 樵夫看不清楚,但又怕真的是自己的斧头,只好又

SPOJ - TSUM Triple Sums FFT+容斥

Triple Sums You're given a sequence s of N distinct integers.Consider all the possible sums of three integers from the sequence at three different indicies.For each obtainable sum output the number of different triples of indicies that generate it.Co

SPOJ 8372. Triple Sums

8372. Triple Sums Problem code: TSUM You're given a sequence s of N distinct integers.Consider all the possible sums of three integers from the sequence at three different indicies.For each obtainable sum output the number of different triples of ind

triple loss 原理以及梯度推导

[理解triple] 如上图所示,triple是一个三元组,这个三元组是这样构成的:从训练数据集中随机选一个样本,该样本称为Anchor,然后再随机选取一个和Anchor (记为x_a)属于同一类的样本和不同类的样本,这两个样本对应的称为Positive (记为x_p)和Negative (记为x_n),由此构成一个(Anchor,Positive,Negative)三元组. [理解triple loss] 有了上面的triple的概念, triple loss就好理解了.针对三元组中的每个元素

Triple transfer json

public class Triple { public Triple(string _S, string _P, string _O) { this._S = _S; this._P = _P; this._O = _O; } public string _S { set; get; } public string _P { set; get; } public string _O { set; get; } } function static void TripleTransferJson(